608

I have first_name, last_name & alias (optional) which I need to search for. So, I need a query to give me all the names that have an alias set.

Only if I could do:

Name.objects.filter(alias!="")

So, what is the equivalent to the above?

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
Val Neekman
  • 17,692
  • 14
  • 63
  • 66

9 Answers9

1097

You could do this:

Name.objects.exclude(alias__isnull=True)

If you need to exclude null values and empty strings, the preferred way to do so is to chain together the conditions like so:

Name.objects.exclude(alias__isnull=True).exclude(alias__exact='')

Chaining these methods together basically checks each condition independently: in the above example, we exclude rows where alias is either null or an empty string, so you get all Name objects that have a not-null, not-empty alias field. The generated SQL would look something like:

SELECT * FROM Name WHERE alias IS NOT NULL AND alias != ""

You can also pass multiple arguments to a single call to exclude, which would ensure that only objects that meet every condition get excluded:

Name.objects.exclude(some_field=True, other_field=True)

Here, rows in which some_field and other_field are true get excluded, so we get all rows where both fields are not true. The generated SQL code would look a little like this:

SELECT * FROM Name WHERE NOT (some_field = TRUE AND other_field = TRUE)

Alternatively, if your logic is more complex than that, you could use Django's Q objects:

from django.db.models import Q
Name.objects.exclude(Q(alias__isnull=True) | Q(alias__exact=''))

For more info see this page and this page in the Django docs.

As an aside: My SQL examples are just an analogy--the actual generated SQL code will probably look different. You'll get a deeper understanding of how Django queries work by actually looking at the SQL they generate.

Sasha Chedygov
  • 127,549
  • 26
  • 102
  • 115
  • 7
    I believe that your edit is wrong: Chaining filter does NOT automatically create an SQL `OR` (only in this case), it produces an SQL `AND`. See this page for reference: https://docs.djangoproject.com/en/dev/topics/db/queries/#chaining-filters The advantage of chaining is that you can mix `exclude` and `filter` to model complicated query conditions. If you want to model a real SQL `OR` you must use a Django Q object: https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects Please edit your edit to reflect this, as the answer is severely misleading as it stands. – shezi Jan 20 '13 at 16:29
  • 1
    @shezi: I meant it more as an analogy--I didn't mean that the actual SQL code is guaranteed to use an `OR` to fuse the conditions. I'll edit my answer to clarify. – Sasha Chedygov Jan 21 '13 at 00:44
  • 1
    Keep in mind that there are at different ways to represent this logic--for instance, `NOT (A AND B)` is equivalent to `NOT A OR NOT B`. I think that makes things confusing to new Django developers who know SQL but are unfamiliar with ORMs. – Sasha Chedygov Jan 21 '13 at 01:17
  • 3
    I know De Morgan's law, and this is my point exactly: Your example only works because it takes advantage to turn the `AND` in the first query into an `OR` because you're using `exclude`. In the general case, it's probably more correct to think of chaining as a `THEN`, i.e. `exclude(A) THEN exclude(B)`. Sorry about the harsh language above. Your answer really is good, but I'm worried about new developers taking your answer too generally. – shezi Feb 10 '13 at 11:25
  • 2
    @shezi: Fair enough. I agree that it's better to think of it in Django terms and not in SQL terms, I just thought that presenting chaining in terms of `AND` and `OR` might be useful for someone coming to Django from an SQL background. For a deeper understanding of Django, I think the docs do a better job than I can. – Sasha Chedygov Feb 13 '13 at 06:23
  • It all becomes tough when you have a related table and want to filter records that have acolumn=FALSE or when the related record is not even existing in the table. You need NOT EXIST query, but... Django (even the latest version 4.1.3) has fucked up ~Q() function. It gets crazy about missing table aliases. – hipertracker Nov 22 '22 at 16:17
  • In case the field is Array. I used this: `Name.objects.exclude(alias__isnull=True).exclude(alias__exact=[])` – Mehrdad Salimi Jan 13 '23 at 22:34
70
Name.objects.filter(alias__gt='',alias__isnull=False)
jbofill
  • 846
  • 6
  • 3
  • 4
    I'm not sure, but I think the `alias__isnull=False` condition is redundant. If the field is `Null` surely it will be excluded by the first clause? – Bobble Oct 29 '15 at 10:16
  • 1
    Aside from my earlier comment/question I think the positive logic here is easier to follow than in some of the other answers. – Bobble Oct 29 '15 at 10:23
  • @Bobble that would depend on the database implementation -- [ordering is delegated to the databse](https://docs.djangoproject.com/en/1.10/ref/models/querysets/#latest) – wpercy Jan 24 '17 at 22:43
  • `alias__gt` was the only thing that worked for JSON type columns where I wanted to exclude empty strings from JSON like `{'something:''}`. So working syntax is: `jsoncolumnname__something__gt=''` – bartgras Mar 30 '20 at 08:42
  • this is super answer if you only have to do a positive check! – Anupam Mar 17 '23 at 12:10
41

Firstly, the Django docs strongly recommend not using NULL values for string-based fields such as CharField or TextField. Read the documentation for the explanation:

https://docs.djangoproject.com/en/dev/ref/models/fields/#null

Solution: You can also chain together methods on QuerySets, I think. Try this:

Name.objects.exclude(alias__isnull=True).exclude(alias="")

That should give you the set you're looking for.

Community
  • 1
  • 1
b3ng0
  • 595
  • 4
  • 6
8

1. When using exclude, keep the following in mind to avoid common mistakes:

Should not add multiple conditions into an exclude() block like filter(). To exclude multiple conditions, you should use multiple exclude().

Example: (NOT a AND NOT b)

Entry.objects.exclude(title='').exclude(headline='')

equal to

SELECT... WHERE NOT title = '' AND NOT headline = ''

======================================================

2. Only use multiple when you really know about it:

Example: NOT (a AND b)

Entry.objects.exclude(title='', headline='')

equal to

SELECT.. WHERE NOT (title = '' AND headline = '')
HoangYell
  • 4,100
  • 37
  • 31
  • 1
    Are you sure about the above to statement? – Hardik Gajjar Jul 30 '20 at 16:29
  • 2
    The [docs](https://docs.djangoproject.com/en/stable/ref/models/querysets/#exclude) are pretty clear that you can include multiple conditions within an `.exclude()` but that they work differently then separate ones. It's the same as the difference between `NOT (a AND b)` and `(NOT a AND NOT b)`. – Tim Tisdall Mar 16 '21 at 19:43
  • Thank you; I've made the necessary changes. – HoangYell Aug 02 '21 at 15:37
7

If you want to exclude null (None), empty string (""), as well as a string containing white spaces (" "), you can use the __regex along with __isnull filter option

Name.objects.filter(
    alias__isnull = False, 
    alias__regex = r"\S+"
)

alias__isnull=False excludes all the columns null columns

aliax__regex = r"\S+" makes sure that the column value contains at least one or more non whitespace characters.

Afsan Abdulali Gujarati
  • 1,375
  • 3
  • 18
  • 30
5

From Django 1.8,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)
Chemical Programmer
  • 4,352
  • 4
  • 37
  • 51
  • 6
    This seems like a "something you *can* do", not something you *should* do. It significantly blooms the query complexity over two simple checks. – Oli Apr 04 '17 at 11:13
4

You can simply do this:

Name.objects.exclude(alias="").exclude(alias=None)

It's really just that simple. filter is used to match and exclude is to match everything but what it specifies. This would evaluate into SQL as NOT alias='' AND alias IS NOT NULL.

Tim Tisdall
  • 9,914
  • 3
  • 52
  • 82
  • This is incorrect. The question aims to exclude empty (`alias=""`) and NULL (`alias=None`) aliases from the query. Yours would include instances with `Name(alias=None)`. – damon Apr 12 '19 at 22:16
  • @damon - I was answering what was the equivalent to `.filter(alias!="")` but not the title. I've edited my answer. However, character fields shouldn't allow NULL values and use the empty string for a non-value (as per convention). – Tim Tisdall Apr 15 '19 at 15:52
2

Another approach using a generic isempty lookup, that can be used with any field.

It can also be used by django rest_framework or other apps that use django lookups:

from distutils.util import strtobool
from django.db.models import Field
from django.db.models.lookups import BuiltinLookup

@Field.register_lookup
class IsEmpty(BuiltinLookup):
    lookup_name = 'isempty'
    prepare_rhs = False

    def as_sql(self, compiler, connection):
        sql, params = compiler.compile(self.lhs)
        condition = self.rhs if isinstance(self.rhs, bool) else bool(strtobool(self.rhs))
        if condition:
            return "%s IS NULL or %s = ''" % (sql, sql), params
        else:
            return "%s <> ''" % sql, params

You can then use it like this:

Name.objects.filter(alias__isempty=False)
rptmat57
  • 3,643
  • 1
  • 27
  • 38
0

this is another simple way to do it .

Name.objects.exclude(alias=None)
ImadOS
  • 425
  • 3
  • 14