[3.1.x] Fixed #31566 -- Fixed aliases crash when chaining values()/values_list() after annotate() with aggregations and subqueries.
Subquery annotation references must be resolved if they are excluded from the GROUP BY clause by a following .values() call. Regression infb3f034f1c
. Thanks Makina Corpus for the report. Backport of42c08ee465
from master
This commit is contained in:
parent
6227173542
commit
8cb87a3f7c
|
@ -2155,6 +2155,15 @@ class Query(BaseExpression):
|
||||||
# SELECT clause which is about to be cleared.
|
# SELECT clause which is about to be cleared.
|
||||||
self.set_group_by(allow_aliases=False)
|
self.set_group_by(allow_aliases=False)
|
||||||
self.clear_select_fields()
|
self.clear_select_fields()
|
||||||
|
elif self.group_by:
|
||||||
|
# Resolve GROUP BY annotation references if they are not part of
|
||||||
|
# the selected fields anymore.
|
||||||
|
group_by = []
|
||||||
|
for expr in self.group_by:
|
||||||
|
if isinstance(expr, Ref) and expr.refs not in field_names:
|
||||||
|
expr = self.annotations[expr.refs]
|
||||||
|
group_by.append(expr)
|
||||||
|
self.group_by = tuple(group_by)
|
||||||
|
|
||||||
self.values_select = tuple(field_names)
|
self.values_select = tuple(field_names)
|
||||||
self.add_fields(field_names, True)
|
self.add_fields(field_names, True)
|
||||||
|
|
|
@ -11,3 +11,7 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed a regression in Django 3.0 by restoring the ability to use field
|
* Fixed a regression in Django 3.0 by restoring the ability to use field
|
||||||
lookups in ``Meta.ordering`` (:ticket:`31538`).
|
lookups in ``Meta.ordering`` (:ticket:`31538`).
|
||||||
|
|
||||||
|
* Fixed a regression in Django 3.0 where ``QuerySet.values()`` and
|
||||||
|
``values_list()`` crashed if a queryset contained an aggregation and a
|
||||||
|
subquery annotation (:ticket:`31566`).
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import datetime
|
import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from unittest import skipIf
|
||||||
|
|
||||||
from django.core.exceptions import FieldDoesNotExist, FieldError
|
from django.core.exceptions import FieldDoesNotExist, FieldError
|
||||||
|
from django.db import connection
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
BooleanField, CharField, Count, DateTimeField, ExpressionWrapper, F, Func,
|
BooleanField, CharField, Count, DateTimeField, Exists, ExpressionWrapper,
|
||||||
IntegerField, NullBooleanField, OuterRef, Q, Subquery, Sum, Value,
|
F, Func, IntegerField, Max, NullBooleanField, OuterRef, Q, Subquery, Sum,
|
||||||
|
Value,
|
||||||
)
|
)
|
||||||
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 Length, Lower
|
||||||
|
@ -619,3 +622,16 @@ class NonAggregateAnnotationTestCase(TestCase):
|
||||||
total_books=Subquery(long_books_qs, output_field=IntegerField()),
|
total_books=Subquery(long_books_qs, output_field=IntegerField()),
|
||||||
).values('name')
|
).values('name')
|
||||||
self.assertCountEqual(publisher_books_qs, [{'name': 'Sams'}, {'name': 'Morgan Kaufmann'}])
|
self.assertCountEqual(publisher_books_qs, [{'name': 'Sams'}, {'name': 'Morgan Kaufmann'}])
|
||||||
|
|
||||||
|
@skipIf(connection.vendor == 'oracle', 'See https://code.djangoproject.com/ticket/31584')
|
||||||
|
def test_annotation_exists_aggregate_values_chaining(self):
|
||||||
|
qs = Book.objects.values('publisher').annotate(
|
||||||
|
has_authors=Exists(Book.authors.through.objects.filter(book=OuterRef('pk'))),
|
||||||
|
max_pubdate=Max('pubdate'),
|
||||||
|
).values_list('max_pubdate', flat=True).order_by('max_pubdate')
|
||||||
|
self.assertCountEqual(qs, [
|
||||||
|
datetime.date(1991, 10, 15),
|
||||||
|
datetime.date(2008, 3, 3),
|
||||||
|
datetime.date(2008, 6, 23),
|
||||||
|
datetime.date(2008, 11, 3),
|
||||||
|
])
|
||||||
|
|
Loading…
Reference in New Issue