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
|
||||
# resolving purpose to facilitate their subsequent removal.
|
||||
refs_subquery = False
|
||||
refs_window = False
|
||||
replacements = {}
|
||||
annotation_select_mask = self.annotation_select_mask
|
||||
for alias, aggregate_expr in aggregate_exprs.items():
|
||||
|
@ -419,6 +420,10 @@ class Query(BaseExpression):
|
|||
getattr(self.annotations[ref], "subquery", False)
|
||||
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)
|
||||
self.annotations[alias] = aggregate
|
||||
replacements[Ref(alias, aggregate)] = aggregate
|
||||
|
@ -451,6 +456,7 @@ class Query(BaseExpression):
|
|||
or self.is_sliced
|
||||
or has_existing_aggregation
|
||||
or refs_subquery
|
||||
or refs_window
|
||||
or qualify
|
||||
or self.distinct
|
||||
or self.combinator
|
||||
|
|
|
@ -9,4 +9,6 @@ Django 4.2.4 fixes several bugs in 4.2.3.
|
|||
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,
|
||||
Variance,
|
||||
When,
|
||||
Window,
|
||||
)
|
||||
from django.db.models.expressions import Func, RawSQL
|
||||
from django.db.models.functions import (
|
||||
|
@ -2207,3 +2208,23 @@ class AggregateAnnotationPruningTests(TestCase):
|
|||
sql = ctx.captured_queries[0]["sql"].lower()
|
||||
self.assertEqual(sql.count("select"), 3, "Subquery wrapping required")
|
||||
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