#32007 closed Bug (fixed)
QuerySet.annotate() with WhereNode() crashes with AttributeError.
Reported by: | Gordon Wrigley | Owned by: | Mariusz Felisiak |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.1 |
Severity: | Release blocker | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I think I've found a regression in 3.1, I'm seeing this across databases and Python versions but only on Django 3.1.
With reference to the polls app the queryset I hit this on is essentially:
Question.objects.values("question_text").annotate( pub_date__count=Count("pub_date", distinct=True), pub_date__is_null=ExpressionWrapper(Q(pub_date=None), output_field=BooleanField()) ).values("question_text", "pub_date__count", "pub_date__is_null")
This results in:
~\.venv\django_tutorial\lib\site-packages\django\db\models\query.py in annotate(self, *args, **kwargs) 1121 clone.query.group_by = True 1122 else: -> 1123 clone.query.set_group_by() 1124 break 1125 ~\.venv\django_tutorial\lib\site-packages\django\db\models\sql\query.py in set_group_by(self, allow_aliases) 1979 if not allow_aliases or alias in column_names: 1980 alias = None -> 1981 group_by_cols = annotation.get_group_by_cols(alias=alias) 1982 group_by.extend(group_by_cols) 1983 self.group_by = tuple(group_by) ~\.venv\django_tutorial\lib\site-packages\django\db\models\expressions.py in get_group_by_cols(self, alias) 867 868 def get_group_by_cols(self, alias=None): --> 869 expression = self.expression.copy() 870 expression.output_field = self.output_field 871 return expression.get_group_by_cols(alias=alias) AttributeError: 'WhereNode' object has no attribute 'copy'
It's a bit of a dumb query but given my usecase https://pypi.org/project/django-data-browser/ that's a little beyond my control.
Still it's kinda surprising that it worked on 3.0 and doesn't on 3.1.
It can be simplified a bit and still get essentially the same result:
Question.objects.annotate( pub_date__count=Count("pub_date", distinct=True), pub_date__is_null=ExpressionWrapper(Q(pub_date=None), output_field=BooleanField()) )
Removing either of the annotate clauses "fixes" it.
Change History (11)
comment:1 by , 4 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Severity: | Normal → Release blocker |
Summary: | AttributeError: 'WhereNode' object has no attribute 'copy' → QuerySet.annotate() with WhereNode() crashes with AttributeError. |
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → Bug |
comment:3 by , 4 years ago
Here is a more useful variant, this is a type thing I actually do on a regular basis, and I guess also means work won't be upgrading to 3.1 until I find a work around.
Question.objects.annotate( pub_date__is_null=ExpressionWrapper(Q(pub_date=None), output_field=BooleanField()) ).values("pub_date__is_null").annotate( id__count=Count("id", distinct=True) ).values("pub_date__is_null", "id__count")
comment:4 by , 4 years ago
Also as a total aside regarding that last snippet it'd be nice if Q objects just were boolean expressions.
comment:5 by , 4 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
Thanks for the report.
Regression in 8a6df55f2dd5131282084a4edfd48f63fbf8c69a.
Reproduced at bcc2befd0e9c1885e45b46d0b0bcdc11def8b249.