16👍
Using Q(pk__in=[])
seems to be a good way to represent this idiom.
As indicated by @fwip and comments below: Django’s ORM nicely recognises this case, knowing this always evaluates to FALSE
. For example:
FooBar.objects.filter(Q(pk__in=[]))
correctly returns an empty QuerySet
without involving any round trip to the database. While:
FooBar.objects.filter(
(Q(pk__in=[]) & Q(foo="bar")) |
Q(hello="world")
)
is optimised down to:
FooBar.objects.filter(
Q(hello="world")
)
i.e. it recognises that Q(pk__in=[])
is always FALSE
, hence the AND
condition can never be TRUE
, so is removed.
To see what queries are actually sent to the database, see: How can I see the raw SQL queries Django is running?
17👍
Note: Sam’s answer is better. I’ve left this answer here instead of deleting it so that you can see the ‘more hacky’ answer that Sam is referring to
Original answer:
What about:
Q(pk__isnull=True)
or
Q(pk=None)
It seems hacky, but it appears to work. For example:
>>> FooBar.objects.filter(Q(x=10)|Q(pk__isnull=True))
[<FooBar: FooBar object>, ...]
>>> FooBar.objects.filter(Q(x=10)&Q(pk__isnull=True))
[]
However, note that it doesn’t work as you might expect when OR’d with an empty Q()
.
>>> FooBar.objects.filter(Q()|Q(pk__isnull=True))
[]
The solution to this might be to use Q(pk__isnull=False)
as the ‘always True Q’.
>>> FooBar.objects.filter(Q(pk__isnull=False)|Q(pk__isnull=True))
[<FooBar: FooBar object>, ...]
>>> FooBar.objects.filter(Q(pk__isnull=False)&Q(pk__isnull=True))
[]
12👍
I don’t have enough reputation to comment, but Sam Mason’s answer (Q(pk__in=[])
) has the advantage that it doesn’t even perform a database query if used alone. Django (v1.10) seems smart enough to recognize that the condition is unsatisfiable, and returns an empty queryset without asking the database.
$ ./manage.py shell_plus
In [1]: from django.db import connection
In [2]: FooBar.objects.filter(Q(pk__in=[]))
Out[2]: <QuerySet []>
In [3]: connection.queries
Out[3]: []