mirror of https://github.com/django/django.git
Fixed #34551 -- Fixed QuerySet.aggregate() crash when referencing subqueries.
Regression in 59bea9efd2
.
Refs #28477.
Thanks Denis Roldán and Mariusz for the test.
This commit is contained in:
parent
2ee01747c3
commit
e5c844d6f2
|
@ -1541,6 +1541,7 @@ class Subquery(BaseExpression, Combinable):
|
|||
template = "(%(subquery)s)"
|
||||
contains_aggregate = False
|
||||
empty_result_set_value = None
|
||||
subquery = True
|
||||
|
||||
def __init__(self, queryset, output_field=None, **extra):
|
||||
# Allow the usage of both QuerySet and sql.Query objects.
|
||||
|
|
|
@ -402,6 +402,7 @@ class Query(BaseExpression):
|
|||
return {}
|
||||
# Store annotation mask prior to temporarily adding aggregations for
|
||||
# resolving purpose to facilitate their subsequent removal.
|
||||
refs_subquery = False
|
||||
replacements = {}
|
||||
annotation_select_mask = self.annotation_select_mask
|
||||
for alias, aggregate_expr in aggregate_exprs.items():
|
||||
|
@ -414,6 +415,10 @@ class Query(BaseExpression):
|
|||
# Temporarily add aggregate to annotations to allow remaining
|
||||
# members of `aggregates` to resolve against each others.
|
||||
self.append_annotation_mask([alias])
|
||||
refs_subquery |= any(
|
||||
getattr(self.annotations[ref], "subquery", False)
|
||||
for ref in aggregate.get_refs()
|
||||
)
|
||||
aggregate = aggregate.replace_expressions(replacements)
|
||||
self.annotations[alias] = aggregate
|
||||
replacements[Ref(alias, aggregate)] = aggregate
|
||||
|
@ -445,6 +450,7 @@ class Query(BaseExpression):
|
|||
isinstance(self.group_by, tuple)
|
||||
or self.is_sliced
|
||||
or has_existing_aggregation
|
||||
or refs_subquery
|
||||
or qualify
|
||||
or self.distinct
|
||||
or self.combinator
|
||||
|
|
|
@ -32,3 +32,7 @@ Bugfixes
|
|||
* Fixed a regression in Django 4.2 that caused a crash of
|
||||
``QuerySet.aggregate()`` with expressions referencing other aggregates
|
||||
(:ticket:`34551`).
|
||||
|
||||
* Fixed a regression in Django 4.2 that caused a crash of
|
||||
``QuerySet.aggregate()`` with aggregates referencing subqueries
|
||||
(:ticket:`34551`).
|
||||
|
|
|
@ -2187,3 +2187,23 @@ class AggregateAnnotationPruningTests(TestCase):
|
|||
mod_count=Count("*")
|
||||
)
|
||||
self.assertEqual(queryset.count(), 1)
|
||||
|
||||
def test_referenced_subquery_requires_wrapping(self):
|
||||
total_books_qs = (
|
||||
Author.book_set.through.objects.values("author")
|
||||
.filter(author=OuterRef("pk"))
|
||||
.annotate(total=Count("book"))
|
||||
)
|
||||
with self.assertNumQueries(1) as ctx:
|
||||
aggregate = (
|
||||
Author.objects.annotate(
|
||||
total_books=Subquery(total_books_qs.values("total"))
|
||||
)
|
||||
.values("pk", "total_books")
|
||||
.aggregate(
|
||||
sum_total_books=Sum("total_books"),
|
||||
)
|
||||
)
|
||||
sql = ctx.captured_queries[0]["sql"].lower()
|
||||
self.assertEqual(sql.count("select"), 3, "Subquery wrapping required")
|
||||
self.assertEqual(aggregate, {"sum_total_books": 3})
|
||||
|
|
Loading…
Reference in New Issue