Skip to content

Commit 3b4a571

Browse files
charettesfelixxm
authored andcommitted
Fixed #34798 -- Fixed QuerySet.aggregate() crash when referencing expressions containing subqueries.
Regression in 59bea9e, complements e5c844d. Refs #28477, #34551. Thanks Haldun Komsuoglu for the report.
1 parent 73b2c63 commit 3b4a571

File tree

4 files changed

+32
-2
lines changed

4 files changed

+32
-2
lines changed

django/db/models/expressions.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,13 @@ def contains_column_references(self):
256256
for expr in self.get_source_expressions()
257257
)
258258

259+
@cached_property
260+
def contains_subquery(self):
261+
return any(
262+
expr and (getattr(expr, "subquery", False) or expr.contains_subquery)
263+
for expr in self.get_source_expressions()
264+
)
265+
259266
def resolve_expression(
260267
self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
261268
):

django/db/models/sql/query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ def get_aggregation(self, using, aggregate_exprs):
452452
# members of `aggregates` to resolve against each others.
453453
self.append_annotation_mask([alias])
454454
refs_subquery |= any(
455-
getattr(self.annotations[ref], "subquery", False)
455+
getattr(self.annotations[ref], "contains_subquery", False)
456456
for ref in aggregate.get_refs()
457457
)
458458
refs_window |= any(

docs/releases/4.2.7.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ Django 4.2.7 fixes several bugs in 4.2.6.
99
Bugfixes
1010
========
1111

12-
...
12+
* Fixed a regression in Django 4.2 that caused a crash of
13+
``QuerySet.aggregate()`` with aggregates referencing expressions containing
14+
subqueries (:ticket:`34798`).

tests/aggregation/tests.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2260,6 +2260,27 @@ def test_referenced_subquery_requires_wrapping(self):
22602260
self.assertEqual(sql.count("select"), 3, "Subquery wrapping required")
22612261
self.assertEqual(aggregate, {"sum_total_books": 3})
22622262

2263+
def test_referenced_composed_subquery_requires_wrapping(self):
2264+
total_books_qs = (
2265+
Author.book_set.through.objects.values("author")
2266+
.filter(author=OuterRef("pk"))
2267+
.annotate(total=Count("book"))
2268+
)
2269+
with self.assertNumQueries(1) as ctx:
2270+
aggregate = (
2271+
Author.objects.annotate(
2272+
total_books=Subquery(total_books_qs.values("total")),
2273+
total_books_ref=F("total_books") / 1,
2274+
)
2275+
.values("pk", "total_books_ref")
2276+
.aggregate(
2277+
sum_total_books=Sum("total_books_ref"),
2278+
)
2279+
)
2280+
sql = ctx.captured_queries[0]["sql"].lower()
2281+
self.assertEqual(sql.count("select"), 3, "Subquery wrapping required")
2282+
self.assertEqual(aggregate, {"sum_total_books": 3})
2283+
22632284
@skipUnlessDBFeature("supports_over_clause")
22642285
def test_referenced_window_requires_wrapping(self):
22652286
total_books_qs = Book.objects.annotate(

0 commit comments

Comments
 (0)