Django
Queryset Filtering
Software Development
Web Development
Python Programming

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:

python
from myapp.models import Book

books = Book.objects.exclude(title="War and Peace")

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:

python
books = Book.objects.filter(in_print=True).exclude(title="War and Peace")

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.

python
1from django.db.models import Q
2from myapp.models import Book
3
4books = Book.objects.filter(~Q(title="War and Peace"))

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:

python
1from django.db.models import Q
2from myapp.models import Book
3
4books = Book.objects.filter(
5    ~Q(title="War and Peace") | Q(year_published__gt=1950)
6)

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:

python
Book.objects.filter(title__ne="War and Peace")

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:

python
from myapp.models import Book

books = Book.objects.exclude(title="War and Peace").exclude(title__isnull=True)

Or with Q objects:

python
1from django.db.models import Q
2from myapp.models import Book
3
4books = Book.objects.filter(~Q(title="War and Peace") & Q(title__isnull=False))

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 complex AND and OR logic

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 __ne lookup in standard Django.
  • Reaching for Q objects immediately when a simple exclude() would be clearer.
  • Forgetting about NULL handling 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 Q object 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.

Course illustration
Course illustration

All Rights Reserved.