Fixed #33468 -- Fixed QuerySet.aggregate() after annotate() crash on aggregates with default.

Thanks Adam Johnson for the report.
This commit is contained in:
Mariusz Felisiak 2022-01-31 11:33:24 +01:00 committed by GitHub
parent beb7ddbcee
commit 71e7c8e737
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 1 deletions

View File

@ -65,7 +65,9 @@ class Aggregate(Func):
if hasattr(default, 'resolve_expression'): if hasattr(default, 'resolve_expression'):
default = default.resolve_expression(query, allow_joins, reuse, summarize) default = default.resolve_expression(query, allow_joins, reuse, summarize)
c.default = None # Reset the default argument before wrapping. 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 @property
def default_alias(self): def default_alias(self):

View File

@ -33,3 +33,7 @@ Bugfixes
* Fixed a duplicate operation regression in Django 4.0 that caused a migration * 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 crash when altering a primary key type for a concrete parent model referenced
by a foreign key (:ticket:`33462`). 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 <aggregate-default>` (:ticket:`33468`).

View File

@ -1630,6 +1630,18 @@ class AggregateTestCase(TestCase):
) )
self.assertAlmostEqual(result['value'], Decimal('61.72'), places=2) 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): def test_exists_none_with_aggregate(self):
qs = Book.objects.all().annotate( qs = Book.objects.all().annotate(
count=Count('id'), count=Count('id'),