Thursday, September 21, 2017

Mixing Q objects and lookups with When conditionals

I have a model in which I was trying to get a count for records that matched three variable values and found an interesting edge case not in the documents for conditional expressions.  Specifically, if you have to use a Q expression for a not query, you can't mix them with lookups.

This is all on Django 1.8 with python 2.7.12

for example, 

SomeModel.objects.aggregate(total = Count(Case(When(~Q(some_field__icontains = 'value'), field_two = 2, field_three = True, then = 1), output_field = IntegerField()))

will result in a TypeError

/home/jason/.virtualenvs/work/lib/python2.7/site-packages/django/db/models/expressions.pyc in __init__(self, condition, then, **lookups)
    687             condition, lookups = Q(**lookups), None
    688         if condition is None or not isinstance(condition, Q) or lookups:
--> 689             raise TypeError("__init__() takes either a Q object or lookups as keyword arguments")
    690         super(When, self).__init__(output_field=None)
    691         self.condition = condition

TypeError: __init__() takes either a Q object or lookups as keyword arguments

However, moving the original to a full ANDed Q expression like 

query  = ~Q(some_field__icontains = 'value') & Q(field_two = 2) & Q(field_three = True)
SomeModel.objects.aggregate(total = Count(Case(When(query, then = 1), output_field = IntegerField()))

works fine.  I couldn't find anything specifically about this in the docs, so is this explicit behavior or an undocumented issue?

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/f374d9a9-f765-4cf0-9691-be90d13318a9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment