How do I do a not equal in Django queryset filtering?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Django does not provide a native __ne lookup for "not equal". Instead, the normal Django ORM approach is to express the inverse condition with exclude() or with a negated Q object when the query is more complex.
Use exclude() For The Simple Case
If you just want every row except the one with a particular value, exclude() is the clearest option:
That query means "give me all Book rows where title is not equal to War and Peace." For straightforward inequality, this is the idiomatic Django answer.
It is also chainable:
That reads naturally and keeps the ORM code easy to review.
Use A Negated Q Object For Complex Logic
When the query mixes "not equal" with other conditions, a negated Q object is often more flexible.
This is logically similar to exclude(title="War and Peace"), but it becomes more useful once several conditions need to be grouped explicitly.
For example:
Now the query says "title is not War and Peace, or the year is greater than 1950." This is the kind of case where Q objects are easier to reason about than a long chain of filter() and exclude() calls.
Do Not Invent A __ne Lookup
A common mistake is trying to write something like this:
That does not work in standard Django because __ne is not a built-in field lookup. If you see it in a codebase, it is either a custom lookup or a bug.
The default ORM tools for inequality are still exclude() and negated Q expressions.
Be Careful With NULL Values
Database NULL handling can surprise people in "not equal" queries. If a field can be null, think about whether null rows should be included or excluded.
For example, suppose you want books whose title is neither War and Peace nor null:
Or with Q objects:
That extra condition matters when your application distinguishes between "a different value" and "no value at all."
Pick The Form That Matches The Query
As a rule of thumb:
- use
exclude(field=value)for a plain not-equal filter - use
~Q(field=value)when the condition must be combined with more complexANDandORlogic
Both are valid. The best choice is the one that makes the query's intent easiest to understand.
Common Pitfalls
- Trying to use a non-existent
__nelookup in standard Django. - Reaching for
Qobjects immediately when a simpleexclude()would be clearer. - Forgetting about
NULLhandling when the field is nullable. - Writing a complex negated query without grouping conditions clearly.
- Assuming
exclude()is always identical to every possible SQL "not equal" interpretation in the presence of nullable columns.
Summary
- Django's normal not-equal tool is
exclude(), not__ne. - Use a negated
Qobject when the query includes more complex boolean logic. - Think carefully about whether nullable rows should count as "not equal" in your application.
- Prefer the form that keeps the ORM query clear and readable.

