From 71e7c8e73712419626f1c2b6ec036e8559a2d667 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Mon, 31 Jan 2022 11:33:24 +0100 Subject: [PATCH] Fixed #33468 -- Fixed QuerySet.aggregate() after annotate() crash on aggregates with default. Thanks Adam Johnson for the report. --- django/db/models/aggregates.py | 4 +++- docs/releases/4.0.2.txt | 4 ++++ tests/aggregation/tests.py | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/django/db/models/aggregates.py b/django/db/models/aggregates.py index 8c4eae79068..bc31b48d8d9 100644 --- a/django/db/models/aggregates.py +++ b/django/db/models/aggregates.py @@ -65,7 +65,9 @@ class Aggregate(Func): if hasattr(default, 'resolve_expression'): default = default.resolve_expression(query, allow_joins, reuse, summarize) c.default = None # Reset the default argument before wrapping. - return Coalesce(c, default, output_field=c._output_field_or_none) + coalesce = Coalesce(c, default, output_field=c._output_field_or_none) + coalesce.is_summary = c.is_summary + return coalesce @property def default_alias(self): diff --git a/docs/releases/4.0.2.txt b/docs/releases/4.0.2.txt index c60dc68224e..e7b98796257 100644 --- a/docs/releases/4.0.2.txt +++ b/docs/releases/4.0.2.txt @@ -33,3 +33,7 @@ Bugfixes * Fixed a duplicate operation regression in Django 4.0 that caused a migration crash when altering a primary key type for a concrete parent model referenced by a foreign key (:ticket:`33462`). + +* Fixed a bug in Django 4.0 that caused a crash of ``QuerySet.aggregate()`` + after ``annotate()`` on an aggregate function with a + :ref:`default ` (:ticket:`33468`). diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py index 87ae945a7eb..5c9aa5d5346 100644 --- a/tests/aggregation/tests.py +++ b/tests/aggregation/tests.py @@ -1630,6 +1630,18 @@ class AggregateTestCase(TestCase): ) self.assertAlmostEqual(result['value'], Decimal('61.72'), places=2) + def test_aggregation_default_after_annotation(self): + result = Publisher.objects.annotate( + double_num_awards=F('num_awards') * 2, + ).aggregate(value=Sum('double_num_awards', default=0)) + self.assertEqual(result['value'], 40) + + def test_aggregation_default_not_in_aggregate(self): + result = Publisher.objects.annotate( + avg_rating=Avg('book__rating', default=2.5), + ).aggregate(Sum('num_awards')) + self.assertEqual(result['num_awards__sum'], 20) + def test_exists_none_with_aggregate(self): qs = Book.objects.all().annotate( count=Count('id'),