How do I do a not equal in Django queryset filtering?

Question:

In Django model QuerySets, I see that there is a __gt and __lt for comparative values, but is there a __ne or != (not equals)? I want to filter out using a not equals. For example, for

Model:
    bool a;
    int x;

I want to do

results = Model.objects.exclude(a=True, x!=5)

The != is not correct syntax. I also tried __ne.

I ended up using:

results = Model.objects.exclude(a=True, x__lt=5).exclude(a=True, x__gt=5)
Asked By: MikeN

||

Answers:

The last bit of code will exclude all objects where x!=5 and a is True. Try this:

results = Model.objects.filter(a=False, x=5)

Remember, the = sign in the above line is assigning False to the parameter a and the number 5 to the parameter x. It’s not checking for equality. Thus, there isn’t really any way to use the != symbol in a query call.

Answered By: Jason Baker

You can use Q objects for this. They can be negated with the ~ operator and combined much like normal Python expressions:

from myapp.models import Entry
from django.db.models import Q

Entry.objects.filter(~Q(id=3))

will return all entries except the one(s) with 3 as their ID:

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]
Answered By: Dave Vogt

the field=value syntax in queries is a shorthand for field__exact=value. That is to say that Django puts query operators on query fields in the identifiers. Django supports the following operators:

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range

date
year
iso_year
month
day
week
week_day
iso_week_day
quarter
time
hour
minute
second

isnull
regex
iregex

I’m sure by combining these with the Q objects as Dave Vogt suggests and using filter() or exclude() as Jason Baker suggests you’ll get exactly what you need for just about any possible query.

Your query appears to have a double negative, you want to exclude all rows where x is not 5, so in other words you want to include all rows where x is 5. I believe this will do the trick:

results = Model.objects.filter(x=5).exclude(a=True)

To answer your specific question, there is no "not equal to" field lookup but that’s probably because Django has both filter and exclude methods available so you can always just switch the logic around to get the desired result.

Answered By: d4nt

While you can filter Models with =, __gt, __gte, __lt, __lte, you cannot use ne or !=. However, you can achieve better filtering using the Q object.

You can avoid chaining QuerySet.filter() and QuerySet.exclude(), and use this:

from django.db.models import Q
object_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')
Answered By: Dami

It’s easy to create a custom lookup, there’s an __ne lookup example in Django’s official documentation.

You need to create the lookup itself first:

from django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

    def as_sql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return '%s <> %s' % (lhs, rhs), params

Then you need to register it:

from django.db.models import Field
Field.register_lookup(NotEqual)

And now you can use the __ne lookup in your queries like this:

results = Model.objects.exclude(a=True, x__ne=5)
Answered By: Dmitrii Mikhailov

You should use filter and exclude like this

results = Model.objects.exclude(a=true).filter(x=5)
Answered By: outoftime

There are three options:

  1. Chain exclude and filter

    results = Model.objects.exclude(a=True).filter(x=5)
    
  2. Use Q() objects and the ~ operator

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
    
  3. Register a custom lookup function

    from django.db.models import Lookup
    from django.db.models import Field
    
    @Field.register_lookup
    class NotEqual(Lookup):
        lookup_name = 'ne'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s <> %s' % (lhs, rhs), params
    

    Which can the be used as usual:

    results = Model.objects.exclude(a=True, x__ne=5)
    
Answered By: ilse2005

Pending design decision. Meanwhile, use exclude()

The Django issue tracker has the remarkable entry #5763,
titled “Queryset doesn’t have a “not equal” filter operator”.
It is remarkable because (as of April 2016) it was
“opened 9 years ago” (in the Django stone age),
“closed 4 years ago”, and
“last changed 5 months ago”.

Read through the discussion, it is interesting.
Basically, some people argue __ne should be added
while others say exclude() is clearer and hence __ne
should not be added.

(I agree with the former, because the latter argument is
roughly equivalent to saying Python should not have != because
it has == and not already…)

Answered By: Lutz Prechelt

What you are looking for are all objects that have either a=false or x=5. In Django, | serves as OR operator between querysets:

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)
Answered By: Gerard

results = Model.objects.filter(a = True).exclude(x = 5)

Generetes this sql:

select * from tablex where a != 0 and x !=5

The sql depends on how your True/False field is represented, and the database engine. The django code is all you need though.

Answered By: M. Dasn

Django-model-values (disclosure: author) provides an implementation of the NotEqual lookup, as in this answer. It also provides syntactic support for it:

from model_values import F
Model.objects.exclude(F.x != 5, a=True)
Answered By: A. Coady

Using exclude and filter

results = Model.objects.filter(x=5).exclude(a=true)
Answered By: jincy mariam

Watch out for lots of incorrect answers to this question!

Gerard’s logic is correct, though it will return a list rather than a queryset (which might not matter).

If you need a queryset, use Q:

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
Answered By: Mark Bailey

This will give your desired result.

from django.db.models import Q
results = Model.objects.exclude(Q(a=True) & ~Q(x=5))

for not equal you can use ~ on an equal query. obviously, Q can be used to reach the equal query.

If we need to exclude/negate based on the sub queryset we can use,

Conditional filter:

When a conditional expression returns a boolean value, it is possible to use it directly in filters. Here non_unique_account_type returns a boolean value. But, still, we can use it in the filter.

>>> non_unique_account_type = Client.objects.filter(
...     account_type=OuterRef('account_type'),
... ).exclude(pk=OuterRef('pk')).values('pk')
>>> Client.objects.filter(~Exists(non_unique_account_type))

In the SQL terms, it evaluates to:

SELECT * FROM client c0
WHERE NOT EXISTS (
  SELECT c1.id
  FROM client c1
  WHERE c1.account_type = c0.account_type AND NOT c1.id = c0.id
)
Answered By: Siva Sankar

This should work

results = Model.objects.filter(x=5).exclude(a=True)
Answered By: Yusuf Ganiyu