[4.2.x] Fixed #34750 -- Fixed QuerySet.count() when grouping by unused multi-valued annotations.

Thanks Toan Vuong for the report.
Thanks Simon Charette for the review.

Regression in 59bea9efd2.
Backport of c9b9a52edc from main
This commit is contained in:
Mariusz Felisiak 2023-08-01 16:16:28 +02:00
parent 2ef2b2ffc0
commit 8808d9da6b
3 changed files with 50 additions and 0 deletions

View File

@ -482,6 +482,11 @@ class Query(BaseExpression):
annotation_mask |= expr.get_refs()
for aggregate in aggregates.values():
annotation_mask |= aggregate.get_refs()
# Avoid eliding expressions that might have an incidence on
# the implicit grouping logic.
for annotation_alias, annotation in self.annotation_select.items():
if annotation.get_group_by_cols():
annotation_mask.add(annotation_alias)
inner_query.set_annotation_mask(annotation_mask)
# Add aggregates to the outer AggregateQuery. This requires making

View File

@ -15,3 +15,7 @@ Bugfixes
* Fixed a regression in Django 4.2 that caused a crash when grouping by a
reference in a subquery (:ticket:`34748`).
* Fixed a regression in Django 4.2 that caused aggregation over query that
uses explicit grouping by multi-valued annotations to group against the wrong
columns (:ticket:`34750`).

View File

@ -2165,6 +2165,47 @@ class AggregateAnnotationPruningTests(TestCase):
self.assertEqual(sql.count("select"), 2, "Subquery wrapping required")
self.assertNotIn("authors_count", sql)
def test_unused_aliased_aggregate_and_annotation_reverse_fk(self):
Book.objects.create(
name="b3",
publisher=self.p2,
pages=1000,
rating=4.2,
price=50,
contact=self.a2,
pubdate=datetime.date.today(),
)
qs = Publisher.objects.annotate(
total_pages=Sum("book__pages"),
good_book=Case(
When(book__rating__gt=4.0, then=Value(True)),
default=Value(False),
),
)
self.assertEqual(qs.count(), 3)
def test_unused_aliased_aggregate_and_annotation_reverse_fk_grouped(self):
Book.objects.create(
name="b3",
publisher=self.p2,
pages=1000,
rating=4.2,
price=50,
contact=self.a2,
pubdate=datetime.date.today(),
)
qs = (
Publisher.objects.values("id", "name")
.annotate(total_pages=Sum("book__pages"))
.annotate(
good_book=Case(
When(book__rating__gt=4.0, then=Value(True)),
default=Value(False),
)
)
)
self.assertEqual(qs.count(), 3)
def test_non_aggregate_annotation_pruned(self):
with CaptureQueriesContext(connection) as ctx:
Book.objects.annotate(