[3.1.x] Fixed #32152 -- Fixed grouping by subquery aliases.

Regression in 42c08ee46539ef44f8658ebb1cbefb408e0d03fe.

Thanks Simon Charette for the review.

Backport of 4ac2d4fa42e1659f328c35b6b8d4761b3419c11a from master
This commit is contained in:
Christian Klus 2020-10-27 13:13:10 -05:00 committed by Mariusz Felisiak
parent 62f6ab2c4a
commit ab951d242e
4 changed files with 34 additions and 3 deletions

View File

@ -2148,8 +2148,10 @@ class Query(BaseExpression):
field_names.append(f) field_names.append(f)
self.set_extra_mask(extra_names) self.set_extra_mask(extra_names)
self.set_annotation_mask(annotation_names) self.set_annotation_mask(annotation_names)
selected = frozenset(field_names + extra_names + annotation_names)
else: else:
field_names = [f.attname for f in self.model._meta.concrete_fields] field_names = [f.attname for f in self.model._meta.concrete_fields]
selected = frozenset(field_names)
# Selected annotations must be known before setting the GROUP BY # Selected annotations must be known before setting the GROUP BY
# clause. # clause.
if self.group_by is True: if self.group_by is True:
@ -2163,7 +2165,7 @@ class Query(BaseExpression):
# the selected fields anymore. # the selected fields anymore.
group_by = [] group_by = []
for expr in self.group_by: for expr in self.group_by:
if isinstance(expr, Ref) and expr.refs not in field_names: if isinstance(expr, Ref) and expr.refs not in selected:
expr = self.annotations[expr.refs] expr = self.annotations[expr.refs]
group_by.append(expr) group_by.append(expr)
self.group_by = tuple(group_by) self.group_by = tuple(group_by)

View File

@ -4,4 +4,11 @@ Django 3.0.11 release notes
*Expected November 2, 2020* *Expected November 2, 2020*
Django 3.0.11 adds compatibility with Python 3.9. Django 3.0.11 fixes a regression in 3.0.7 and adds compatibility with Python
3.9.
Bugfixes
========
* Fixed a regression in Django 3.0.7 that didn't use ``Subquery()`` aliases in
the ``GROUP BY`` clause (:ticket:`32152`).

View File

@ -57,3 +57,6 @@ Bugfixes
* Fixed a regression in Django 3.1 that caused incorrect textarea layout on * Fixed a regression in Django 3.1 that caused incorrect textarea layout on
medium-sized screens in the admin change form view with the sidebar open medium-sized screens in the admin change form view with the sidebar open
(:ticket:`32127`). (:ticket:`32127`).
* Fixed a regression in Django 3.0.7 that didn't use ``Subquery()`` aliases in
the ``GROUP BY`` clause (:ticket:`32152`).

View File

@ -10,7 +10,7 @@ from django.db.models import (
NullBooleanField, OuterRef, Q, Subquery, Sum, Value, When, NullBooleanField, OuterRef, Q, Subquery, Sum, Value, When,
) )
from django.db.models.expressions import RawSQL from django.db.models.expressions import RawSQL
from django.db.models.functions import Length, Lower from django.db.models.functions import ExtractYear, Length, Lower
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase, skipUnlessDBFeature
from .models import ( from .models import (
@ -664,6 +664,25 @@ class NonAggregateAnnotationTestCase(TestCase):
datetime.date(2008, 11, 3), datetime.date(2008, 11, 3),
]) ])
@skipUnlessDBFeature('supports_subqueries_in_group_by')
def test_annotation_subquery_and_aggregate_values_chaining(self):
qs = Book.objects.annotate(
pub_year=ExtractYear('pubdate')
).values('pub_year').annotate(
top_rating=Subquery(
Book.objects.filter(
pubdate__year=OuterRef('pub_year')
).order_by('-rating').values('rating')[:1]
),
total_pages=Sum('pages'),
).values('pub_year', 'total_pages', 'top_rating')
self.assertCountEqual(qs, [
{'pub_year': 1991, 'top_rating': 5.0, 'total_pages': 946},
{'pub_year': 1995, 'top_rating': 4.0, 'total_pages': 1132},
{'pub_year': 2007, 'top_rating': 4.5, 'total_pages': 447},
{'pub_year': 2008, 'top_rating': 4.0, 'total_pages': 1178},
])
@skipIf( @skipIf(
connection.vendor == 'mysql' and 'ONLY_FULL_GROUP_BY' in connection.sql_mode, connection.vendor == 'mysql' and 'ONLY_FULL_GROUP_BY' in connection.sql_mode,
'GROUP BY optimization does not work properly when ONLY_FULL_GROUP_BY ' 'GROUP BY optimization does not work properly when ONLY_FULL_GROUP_BY '