Hi,
I use django-4.1.1 and I’m having unexpected results to queries involving multiple Count() annotation used in a filter expression. I can reproduce this behavior with the User/Group models from django.contrib.auth.
In the following, I’m adding 2 Count() to the User queryset, with one of them using a conditional involving an empty set:
User.objects \
.annotate(num1=Count('groups'), num2=Count('groups', filter=Q(groups__in=[]))) \
.values('pk', 'num1', 'num2')
This yields the following result:
<QuerySet [{'pk': 1, 'num1': 0, 'num2': 0}, {'pk': 2, 'num1': 0, 'num2': 0}, {'pk': 3, 'num1': 1, 'num2': 0}]>
However, if I add the filter num1 >= num2
, as in
User.objects \
.annotate(num1=Count('groups'), num2=Count('groups', filter=Q(groups__in=[]))) \
.filter(num1__gte=F('num2')) \
.values('pk', 'num1', 'num2')
Then this yields an empty result set:
<QuerySet []>
I would have expected to get the same results as in the first query above, given the values in the database (the condition num1 >= num2
is true for all User instances). Also looking at len(django.db.connection.queries)
before and after, I can see that this last query does not even trigger any request to the postgres database, it seems that django decides to skip the query altogether and return and empty queryset.
And if I force the Count condition to use a non-trivial queryset, although the result is also empty, it then works as expected. E.g.:
User.objects \
.annotate(num1=Count('groups'), num2=Count('groups', filter=Q(groups__in=Group.objects.filter(pk=0)))) \
.filter(num1__gte=F('num2')) \
.values('pk', 'num1', 'num2')
Yields
<QuerySet [{'pk': 1, 'num1': 0, 'num2': 0}, {'pk': 2, 'num1': 0, 'num2': 0}, {'pk': 3, 'num1': 1, 'num2': 0}]>
I’m hoping to get some insight on what I’m doing wrong. Thanks.