mirror of https://github.com/django/django.git
Fixed #34717 -- Fixed QuerySet.aggregate() crash when referencing window functions.
Regression in 59bea9efd2
.
Refs #28477.
Thanks younes-chaoui for the report.
This commit is contained in:
parent
f8c43aca46
commit
68912e4f6f
|
@ -403,6 +403,7 @@ class Query(BaseExpression):
|
||||||
# Store annotation mask prior to temporarily adding aggregations for
|
# Store annotation mask prior to temporarily adding aggregations for
|
||||||
# resolving purpose to facilitate their subsequent removal.
|
# resolving purpose to facilitate their subsequent removal.
|
||||||
refs_subquery = False
|
refs_subquery = False
|
||||||
|
refs_window = False
|
||||||
replacements = {}
|
replacements = {}
|
||||||
annotation_select_mask = self.annotation_select_mask
|
annotation_select_mask = self.annotation_select_mask
|
||||||
for alias, aggregate_expr in aggregate_exprs.items():
|
for alias, aggregate_expr in aggregate_exprs.items():
|
||||||
|
@ -419,6 +420,10 @@ class Query(BaseExpression):
|
||||||
getattr(self.annotations[ref], "subquery", False)
|
getattr(self.annotations[ref], "subquery", False)
|
||||||
for ref in aggregate.get_refs()
|
for ref in aggregate.get_refs()
|
||||||
)
|
)
|
||||||
|
refs_window |= any(
|
||||||
|
getattr(self.annotations[ref], "contains_over_clause", True)
|
||||||
|
for ref in aggregate.get_refs()
|
||||||
|
)
|
||||||
aggregate = aggregate.replace_expressions(replacements)
|
aggregate = aggregate.replace_expressions(replacements)
|
||||||
self.annotations[alias] = aggregate
|
self.annotations[alias] = aggregate
|
||||||
replacements[Ref(alias, aggregate)] = aggregate
|
replacements[Ref(alias, aggregate)] = aggregate
|
||||||
|
@ -451,6 +456,7 @@ class Query(BaseExpression):
|
||||||
or self.is_sliced
|
or self.is_sliced
|
||||||
or has_existing_aggregation
|
or has_existing_aggregation
|
||||||
or refs_subquery
|
or refs_subquery
|
||||||
|
or refs_window
|
||||||
or qualify
|
or qualify
|
||||||
or self.distinct
|
or self.distinct
|
||||||
or self.combinator
|
or self.combinator
|
||||||
|
|
|
@ -9,4 +9,6 @@ Django 4.2.4 fixes several bugs in 4.2.3.
|
||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
||||||
* ...
|
* Fixed a regression in Django 4.2 that caused a crash of
|
||||||
|
``QuerySet.aggregate()`` with aggregates referencing window functions
|
||||||
|
(:ticket:`34717`).
|
||||||
|
|
|
@ -28,6 +28,7 @@ from django.db.models import (
|
||||||
Value,
|
Value,
|
||||||
Variance,
|
Variance,
|
||||||
When,
|
When,
|
||||||
|
Window,
|
||||||
)
|
)
|
||||||
from django.db.models.expressions import Func, RawSQL
|
from django.db.models.expressions import Func, RawSQL
|
||||||
from django.db.models.functions import (
|
from django.db.models.functions import (
|
||||||
|
@ -2207,3 +2208,23 @@ class AggregateAnnotationPruningTests(TestCase):
|
||||||
sql = ctx.captured_queries[0]["sql"].lower()
|
sql = ctx.captured_queries[0]["sql"].lower()
|
||||||
self.assertEqual(sql.count("select"), 3, "Subquery wrapping required")
|
self.assertEqual(sql.count("select"), 3, "Subquery wrapping required")
|
||||||
self.assertEqual(aggregate, {"sum_total_books": 3})
|
self.assertEqual(aggregate, {"sum_total_books": 3})
|
||||||
|
|
||||||
|
@skipUnlessDBFeature("supports_over_clause")
|
||||||
|
def test_referenced_window_requires_wrapping(self):
|
||||||
|
total_books_qs = Book.objects.annotate(
|
||||||
|
avg_publisher_pages=Coalesce(
|
||||||
|
Window(Avg("pages"), partition_by=F("publisher")),
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with self.assertNumQueries(1) as ctx:
|
||||||
|
aggregate = total_books_qs.aggregate(
|
||||||
|
sum_avg_publisher_pages=Sum("avg_publisher_pages"),
|
||||||
|
books_count=Count("id"),
|
||||||
|
)
|
||||||
|
sql = ctx.captured_queries[0]["sql"].lower()
|
||||||
|
self.assertEqual(sql.count("select"), 2, "Subquery wrapping required")
|
||||||
|
self.assertEqual(
|
||||||
|
aggregate,
|
||||||
|
{"sum_avg_publisher_pages": 1100.0, "books_count": 2},
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue