ChatGPT解决这个技术问题 Extra ChatGPT

How to filter empty or NULL names in a QuerySet?

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?


S
Sasha Chedygov

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.


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: docs.djangoproject.com/en/dev/topics/db/queries/… 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: docs.djangoproject.com/en/dev/topics/db/queries/… Please edit your edit to reflect this, as the answer is severely misleading as it stands.
@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.
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.
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: 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.
j
jbofill
Name.objects.filter(alias__gt='',alias__isnull=False)

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?
Aside from my earlier comment/question I think the positive logic here is easier to follow than in some of the other answers.
@Bobble that would depend on the database implementation -- ordering is delegated to the databse
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=''
C
Community

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.


H
HoangYell

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 = '')

Are you sure about the above to statement?
The docs 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).
Thank you; I've made the necessary changes.
C
Chemical Programmer

From Django 1.8,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)

This seems like a "something you can do", not something you should do. It significantly blooms the query complexity over two simple checks.
A
Afsan Abdulali Gujarati

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.


T
Tim Tisdall

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.


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 - 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).
I
ImadOS

this is another simple way to do it .

Name.objects.exclude(alias=None)

None is not the same thing as "".
r
rptmat57

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)