mirror of
https://github.com/django/django.git
synced 2024-12-25 18:46:22 +00:00
[4.2.x] Fixed #34717 -- Fixed QuerySet.aggregate() crash when referencing window functions.
Regression in59bea9efd2
. Refs #28477. Thanks younes-chaoui for the report. Backport of68912e4f6f
from main
This commit is contained in:
parent
c646412a75
commit
7a67b065d7
@ -390,6 +390,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():
|
||||
@ -406,6 +407,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
|
||||
@ -438,6 +443,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
Block a user