summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/models/query.py12
-rw-r--r--tests/aggregation/tests.py10
2 files changed, 20 insertions, 2 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 6c78fbc4b3..8d888447cd 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -17,7 +17,7 @@ from django.db import (
from django.db.models import AutoField, DateField, DateTimeField, sql
from django.db.models.constants import LOOKUP_SEP
from django.db.models.deletion import Collector
-from django.db.models.expressions import Case, Expression, F, Value, When
+from django.db.models.expressions import Case, Expression, F, Ref, Value, When
from django.db.models.functions import Cast, Trunc
from django.db.models.query_utils import FilteredRelation, Q
from django.db.models.sql.constants import CURSOR, GET_ITERATOR_CHUNK_SIZE
@@ -386,8 +386,16 @@ class QuerySet:
query = self.query.chain()
for (alias, aggregate_expr) in kwargs.items():
query.add_annotation(aggregate_expr, alias, is_summary=True)
- if not query.annotations[alias].contains_aggregate:
+ annotation = query.annotations[alias]
+ if not annotation.contains_aggregate:
raise TypeError("%s is not an aggregate expression" % alias)
+ for expr in annotation.get_source_expressions():
+ if expr.contains_aggregate and isinstance(expr, Ref) and expr.refs in kwargs:
+ name = expr.refs
+ raise exceptions.FieldError(
+ "Cannot compute %s('%s'): '%s' is an aggregate"
+ % (annotation.name, name, name)
+ )
return query.get_aggregation(self.db, kwargs)
def count(self):
diff --git a/tests/aggregation/tests.py b/tests/aggregation/tests.py
index 1f6baa70ff..f8aeceb2d0 100644
--- a/tests/aggregation/tests.py
+++ b/tests/aggregation/tests.py
@@ -1004,6 +1004,16 @@ class AggregateTestCase(TestCase):
self.assertEqual(author.sum_age, other_author.sum_age)
+ def test_aggregate_over_aggregate(self):
+ msg = "Cannot compute Avg('age'): 'age' is an aggregate"
+ with self.assertRaisesMessage(FieldError, msg):
+ Author.objects.annotate(
+ age_alias=F('age'),
+ ).aggregate(
+ age=Sum(F('age')),
+ avg_age=Avg(F('age')),
+ )
+
def test_annotated_aggregate_over_annotated_aggregate(self):
with self.assertRaisesMessage(FieldError, "Cannot compute Sum('id__max'): 'id__max' is an aggregate"):
Book.objects.annotate(Max('id')).annotate(Sum('id__max'))