`models.py`
{{{
class School(models.Model):
"""A school"""
class Director(models.Model):
school = models.ForeignKey(School, on_delete=models.CASCADE)
speciality = models.CharField(max_length=200)
}}}
It is not possible to run this code:
{{{#!python
>>> School.objects.annotate(
>>> speciality=Subquery(Director.objects.values('speciality')[:1]),
>>> has_speciality=Q(speciality__isnull=False)
>>> ).count()
…
AttributeError: 'WhereNode' object has no attribute 'is_summary'
}}}
Reverting this precise commit seems to fix the issue :
https://github.com/django/django/commit/b64db05b9cedd96905d637a2d824cbbf428e40e7
The request is a bit exotic, I don't know if it should be supported.
This is the first ticket I open, I can clarify/submit a merge request if
needed.
--
Ticket URL: <https://code.djangoproject.com/ticket/34024>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by David Sanders):
Confirmed on latest main.
Full traceback from ipython:
{{{
[ins] In [1]: School.objects.annotate(
...:
speciality=Subquery(Director.objects.values('speciality')[:1]),
...: has_speciality=Q(speciality__isnull=False)
...: ).count()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call
last)
Cell In [1], line 4
1 School.objects.annotate(
2
speciality=Subquery(Director.objects.values('speciality')[:1]),
3 has_speciality=Q(speciality__isnull=False)
----> 4 ).count()
File ~/projects/django/django/db/models/query.py:621, in
QuerySet.count(self)
618 if self._result_cache is not None:
619 return len(self._result_cache)
--> 621 return self.query.get_count(using=self.db)
File ~/projects/django/django/db/models/sql/query.py:554, in
Query.get_count(self, using)
552 obj = self.clone()
553 obj.add_annotation(Count("*"), alias="__count", is_summary=True)
--> 554 return obj.get_aggregation(using, ["__count"])["__count"]
File ~/projects/django/django/db/models/sql/query.py:503, in
Query.get_aggregation(self, using, added_aggregate_names)
501 for alias, expression in
list(inner_query.annotation_select.items()):
502 annotation_select_mask = inner_query.annotation_select_mask
--> 503 if expression.is_summary:
504 expression, col_cnt = inner_query.rewrite_cols(expression,
col_cnt)
505 outer_query.annotations[alias] =
expression.relabeled_clone(
506 relabels
507 )
AttributeError: 'WhereNode' object has no attribute 'is_summary'
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34024#comment:1>
* stage: Unreviewed => Accepted
--
Ticket URL: <https://code.djangoproject.com/ticket/34024#comment:2>
* cc: David Sanders (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/34024#comment:3>
Comment (by David Sanders):
Here's a simple boiled down failing test case:
{{{
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 1bd72dd8b8..c6d9b05761 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -1312,6 +1312,10 @@ class Queries1Tests(TestCase):
)
self.assertSequenceEqual(Note.objects.exclude(negate=True),
[self.n3])
+ def test_count_on_annotation(self):
+ # Ticket: #34024
+ Tag.objects.annotate(has_pk=~Q(pk=None)).count()
+
class Queries2Tests(TestCase):
@classmethod
}}}
results
{{{
E
======================================================================
ERROR: test_count_on_annotation (queries.tests.Queries1Tests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/davids/projects/django/tests/queries/tests.py", line 1317,
in test_count_on_annotation
Tag.objects.annotate(has_pk=~Q(pk=None)).count()
File "/Users/davids/projects/django/django/db/models/query.py", line
621, in count
return self.query.get_count(using=self.db)
File "/Users/davids/projects/django/django/db/models/sql/query.py", line
554, in get_count
return obj.get_aggregation(using, ["__count"])["__count"]
File "/Users/davids/projects/django/django/db/models/sql/query.py", line
503, in get_aggregation
if expression.is_summary:
AttributeError: 'WhereNode' object has no attribute 'is_summary'
----------------------------------------------------------------------
Ran 1 test in 0.014s
FAILED (errors=1)
Destroying test database for alias 'default'...
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34024#comment:4>
* cc: David Wobrock (added)
* owner: nobody => David Sanders
* has_patch: 0 => 1
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/34024#comment:5>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"1674c70525bc370132a1db27617e468081920d11" 1674c705]:
{{{
#!CommitTicketReference repository=""
revision="1674c70525bc370132a1db27617e468081920d11"
Fixed #34024 -- Fixed crash when aggregating querysets with Q objects
annotations.
This reverts b64db05b9cedd96905d637a2d824cbbf428e40e7.
It was reasonable to assume it was unnecessary code as there were
no failing tests upon its removal. This commit adds the necessary
regression tests for the failing condition identified in #34024
alongside the original tests added in the PR for which
WhereNode.is_summary was introduced.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/34024#comment:6>