From bdc07f176eb7c099ac3fdc42ebaadd48b7f67409 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Fri, 8 Mar 2019 11:26:53 -0500 Subject: [PATCH] Fixed #30188 -- Fixed a crash when aggregating over a subquery annotation. --- django/db/models/sql/query.py | 4 ++-- tests/expressions/tests.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 4f2fe5acb5..74aed551a3 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -22,7 +22,7 @@ from django.db import DEFAULT_DB_ALIAS, NotSupportedError, connections from django.db.models.aggregates import Count from django.db.models.constants import LOOKUP_SEP from django.db.models.expressions import ( - BaseExpression, Col, F, OuterRef, Ref, SimpleCol, + BaseExpression, Col, F, OuterRef, Ref, SimpleCol, Subquery, ) from django.db.models.fields import Field from django.db.models.fields.related_lookups import MultiColSource @@ -382,7 +382,7 @@ class Query(BaseExpression): # before the contains_aggregate/is_summary condition below. new_expr, col_cnt = self.rewrite_cols(expr, col_cnt) new_exprs.append(new_expr) - elif isinstance(expr, Col) or (expr.contains_aggregate and not expr.is_summary): + elif isinstance(expr, (Col, Subquery)) or (expr.contains_aggregate and not expr.is_summary): # Reference to column. Make sure the referenced column # is selected. col_cnt += 1 diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index cc03e83ff4..bb448745c8 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -551,6 +551,19 @@ class BasicExpressionsTests(TestCase): ) self.assertEqual(qs.get().float, 1.2) + @skipUnlessDBFeature('supports_subqueries_in_group_by') + def test_aggregate_subquery_annotation(self): + aggregate = Company.objects.annotate( + ceo_salary=Subquery( + Employee.objects.filter( + id=OuterRef('ceo_id'), + ).values('salary') + ), + ).aggregate( + ceo_salary_gt_20=Count('pk', filter=Q(ceo_salary__gt=20)), + ) + self.assertEqual(aggregate, {'ceo_salary_gt_20': 1}) + def test_explicit_output_field(self): class FuncA(Func): output_field = models.CharField()