Opened 12 months ago
Last modified 12 months ago
#34975 closed Bug
Getting refs is not work properly with models.Window and aggregation — at Initial Version
Reported by: | Sergey Nesterenko | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 4.2 |
Severity: | Release blocker | Keywords: | QuerySet, Window, Aggregate, F |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I found out that getting refs in QuerySet doesn't work with models.Window when I try to use aggregate method. It happened when I tried to update Django to 4.2.7.
For example:
MyModel.objects.annotate( new_ordering=Window(RowNumber(), order_by=[F('ordering')]) ).aggregate( wrong_count=Count('id', filter=Q(ordering=F('new_ordering'))) )
And as a result, it fails with:
Traceback (most recent call last): File "/main.py", line 38, in <module> result = ordering_query.aggregate( File "/python3.10/site-packages/django/db/models/query.py", line 592, in aggregate return self.query.chain().get_aggregation(self.db, kwargs) File "/python3.10/site-packages/django/db/models/sql/query.py", line 398, in get_aggregation aggregate = aggregate_expr.resolve_expression( File "/python3.10/site-packages/django/db/models/aggregates.py", line 70, in resolve_expression for ref in c.get_refs(): File "/python3.10/site-packages/django/db/models/expressions.py", line 418, in get_refs refs |= expr.get_refs() File "/python3.10/site-packages/django/db/models/sql/where.py", line 233, in get_refs refs |= child.get_refs() File "/python3.10/site-packages/django/db/models/expressions.py", line 418, in get_refs refs |= expr.get_refs() File "/python3.10/site-packages/django/db/models/expressions.py", line 418, in get_refs refs |= expr.get_refs() AttributeError: 'NoneType' object has no attribute 'get_refs'
It happens because of Window.get_source_expressions return:
def get_source_expressions(self): return [self.source_expression, self.partition_by, self.order_by, self.frame]
and if we don't specify 'frame' (for example) it will be None in the list.
And in models.aggregates.Aggregate.resolve_expression when we try to find all refs https://github.com/django/django/blob/47f9b8dca16b1fdc054b338d81eb080eabad0edf/django/db/models/aggregates.py#L70C30-L70C30 it fails because of we have None in Window.get_source_expressions
def get_refs(self): refs = set() for expr in self.get_source_expressions(): refs |= expr.get_refs() return refs