When Django's ORM Uses Q?

446 views Asked by At

I am trying to use Django's Q functionality to generate some AND and OR SQL queries, but unfortunately I can't seem to figure out how and when Django generates it's conditionals. I had a more complex query but I decided to pare it down to see what was going on.

Example without Q():

>>> MyObject.objects.filter(status='VALUE').count()
6

And now Q():

>>> MyObject.objects.filter(Q(status='VALUE')).count()
22

And the queries this generates from django.db.connection:

[{'time': '0.001', 'sql': 'SELECT COUNT(*) FROM "myobjects_myobject" WHERE "myobjects_myobject"."status" = E\'VALUE\' '}, {'time': '0.001', 'sql': 'SELECT COUNT(*) FROM "myobjects_myobject"'}]

And then I add a another value:

>>> MyObject.objects.filter(Q(status='VALUE'), Q(created_date__lt=a_date_value)).count()
22

But when I reverse that order I get:

>>> MyObject.objects.filter(Q(created_date__lt=a_date_value), Q(status='VALUE'), ).count()
6

With the SQL:

[{'time': '0.001', 'sql': 'SELECT COUNT(*) FROM "myobjects_myobject" WHERE "myobjects_myobject"."created_date" < E\'2011-02-09 00:24:55.927825\' '}, {'time': '0.001', 'sql': 'SELECT COUNT(*) FROM "myobjects_myobject" WHERE "myobjects_myobject"."status" = E\'VALUE\' '}

So it looks like to me like it's ignoring the first Q value each time - is this the expected behavior?

1

There are 1 answers

0
Wolph On BEST ANSWER

If this is the actual code you've executed than you've stumbled upon a bug in Django.

The following should have identical results:

>>> MyObject.objects.filter(status='VALUE').count()
>>> MyObject.objects.filter(Q(status='VALUE')).count()

It doesn't really matter that much though, Q objects are never really needed.

Instead of this:

>>> qs = MyObject.objects.all()
>>> qs.filter(Q(status='VALUE') | Q(status='UNKNOWN')).count()

You can also use this:

>>> qs = MyObject.objects.all()
>>> (qs.filter(status='VALUE') | qs.filter(status='UNKNOWN')).count()