Always False Q object

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))
[]

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]: []

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?

Tags:

Django