Fixed #31880 -- Made QuerySet.aggregate() raise FieldError when aggregating over aggregation aliases.
This commit is contained in:
parent
01a7af09b9
commit
058747b77a
|
@ -17,7 +17,7 @@ from django.db import (
|
||||||
from django.db.models import AutoField, DateField, DateTimeField, sql
|
from django.db.models import AutoField, DateField, DateTimeField, sql
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.db.models.deletion import Collector
|
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.functions import Cast, Trunc
|
||||||
from django.db.models.query_utils import FilteredRelation, Q
|
from django.db.models.query_utils import FilteredRelation, Q
|
||||||
from django.db.models.sql.constants import CURSOR, GET_ITERATOR_CHUNK_SIZE
|
from django.db.models.sql.constants import CURSOR, GET_ITERATOR_CHUNK_SIZE
|
||||||
|
@ -386,8 +386,16 @@ class QuerySet:
|
||||||
query = self.query.chain()
|
query = self.query.chain()
|
||||||
for (alias, aggregate_expr) in kwargs.items():
|
for (alias, aggregate_expr) in kwargs.items():
|
||||||
query.add_annotation(aggregate_expr, alias, is_summary=True)
|
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)
|
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)
|
return query.get_aggregation(self.db, kwargs)
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
|
|
|
@ -1004,6 +1004,16 @@ class AggregateTestCase(TestCase):
|
||||||
|
|
||||||
self.assertEqual(author.sum_age, other_author.sum_age)
|
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):
|
def test_annotated_aggregate_over_annotated_aggregate(self):
|
||||||
with self.assertRaisesMessage(FieldError, "Cannot compute Sum('id__max'): 'id__max' is an aggregate"):
|
with self.assertRaisesMessage(FieldError, "Cannot compute Sum('id__max'): 'id__max' is an aggregate"):
|
||||||
Book.objects.annotate(Max('id')).annotate(Sum('id__max'))
|
Book.objects.annotate(Max('id')).annotate(Sum('id__max'))
|
||||||
|
|
Loading…
Reference in New Issue