Opened 2 years ago

Closed 2 years ago

#34024 closed Bug (fixed)

'WhereNode' object has no attribute 'is_summary' when counting a queryset with annotation from a subquery

Reported by: Valentin Rigal Owned by: David Sanders
Component: Database layer (models, ORM) Version: 4.1
Severity: Normal Keywords:
Cc: David Sanders, David Wobrock Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I reproduced on a blank project (4.0 and 4.1 with a Postgres database) using this use case:

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:

>>> 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.

Change History (6)

comment:1 by David Sanders, 2 years ago

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'

comment:2 by Simon Charette, 2 years ago

Triage Stage: UnreviewedAccepted

comment:3 by David Sanders, 2 years ago

Cc: David Sanders added

comment:4 by David Sanders, 2 years ago

FYI: none of the original tests from the PR introducing WhereNode.is_summary were testing with Q

Here's a simplified failing test case to go alongside those added with the PR:

diff --git a/tests/aggregation_regress/tests.py b/tests/aggregation_regress/tests.py
index e15e7e41d9..cc92029135 100644
--- a/tests/aggregation_regress/tests.py
+++ b/tests/aggregation_regress/tests.py
@@ -554,6 +554,10 @@ class AggregationTests(TestCase):
             325,
         )

+    def test_q_annotation_aggregate(self):
+        # Ensure aggregation works with annotations using Q objects
+        Book.objects.annotate(has_pk=~Q(pk=None)).count()
+
     def test_decimal_aggregate_annotation_filter(self):
         """
         Filtering on an aggregate annotation with Decimal values should work.
Last edited 2 years ago by David Sanders (previous) (diff)

comment:5 by David Wobrock, 2 years ago

Cc: David Wobrock added
Has patch: set
Owner: changed from nobody to David Sanders
Status: newassigned

comment:6 by GitHub <noreply@…>, 2 years ago

Resolution: fixed
Status: assignedclosed

In 1674c705:

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.

Note: See TracTickets for help on using tickets.
Back to Top