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?
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.
Name.objects.filter(alias__gt='',alias__isnull=False)
alias__isnull=False
condition is redundant. If the field is Null
surely it will be excluded by the first clause?
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=''
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.
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 = '')
.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)
.
From Django 1.8,
from django.db.models.functions import Length
Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)
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.
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
.
alias=""
) and NULL (alias=None
) aliases from the query. Yours would include instances with Name(alias=None)
.
.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).
this is another simple way to do it .
Name.objects.exclude(alias=None)
None
is not the same thing as ""
.
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)
Success story sharing
OR
(only in this case), it produces an SQLAND
. See this page for reference: docs.djangoproject.com/en/dev/topics/db/queries/… The advantage of chaining is that you can mixexclude
andfilter
to model complicated query conditions. If you want to model a real SQLOR
you must use a Django Q object: docs.djangoproject.com/en/dev/topics/db/queries/… Please edit your edit to reflect this, as the answer is severely misleading as it stands.OR
to fuse the conditions. I'll edit my answer to clarify.NOT (A AND B)
is equivalent toNOT A OR NOT B
. I think that makes things confusing to new Django developers who know SQL but are unfamiliar with ORMs.AND
in the first query into anOR
because you're usingexclude
. In the general case, it's probably more correct to think of chaining as aTHEN
, 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.AND
andOR
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.