Skip to content

Commit afceb22

Browse files
charettesfelixxm
authored andcommitted
[3.0.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 in fb3f034. Thanks Makina Corpus for the report. Backport of 42c08ee from master
1 parent 6e8a11e commit afceb22

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

django/db/models/sql/query.py

+9
Original file line numberDiff line numberDiff line change
@@ -2141,6 +2141,15 @@ def set_values(self, fields):
21412141
# SELECT clause which is about to be cleared.
21422142
self.set_group_by(allow_aliases=False)
21432143
self.clear_select_fields()
2144+
elif self.group_by:
2145+
# Resolve GROUP BY annotation references if they are not part of
2146+
# the selected fields anymore.
2147+
group_by = []
2148+
for expr in self.group_by:
2149+
if isinstance(expr, Ref) and expr.refs not in field_names:
2150+
expr = self.annotations[expr.refs]
2151+
group_by.append(expr)
2152+
self.group_by = tuple(group_by)
21442153

21452154
self.values_select = tuple(field_names)
21462155
self.add_fields(field_names, True)

docs/releases/3.0.7.txt

+4
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ Bugfixes
1111

1212
* Fixed a regression in Django 3.0 by restoring the ability to use field
1313
lookups in ``Meta.ordering`` (:ticket:`31538`).
14+
15+
* Fixed a regression in Django 3.0 where ``QuerySet.values()`` and
16+
``values_list()`` crashed if a queryset contained an aggregation and a
17+
subquery annotation (:ticket:`31566`).

tests/annotations/tests.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import datetime
22
from decimal import Decimal
3+
from unittest import skipIf
34

45
from django.core.exceptions import FieldDoesNotExist, FieldError
6+
from django.db import connection
57
from django.db.models import (
6-
BooleanField, CharField, Count, DateTimeField, ExpressionWrapper, F, Func,
7-
IntegerField, NullBooleanField, OuterRef, Q, Subquery, Sum, Value,
8+
BooleanField, CharField, Count, DateTimeField, Exists, ExpressionWrapper,
9+
F, Func, IntegerField, Max, NullBooleanField, OuterRef, Q, Subquery, Sum,
10+
Value,
811
)
912
from django.db.models.expressions import RawSQL
1013
from django.db.models.functions import Length, Lower
@@ -619,3 +622,16 @@ def test_annotation_filter_with_subquery(self):
619622
total_books=Subquery(long_books_qs, output_field=IntegerField()),
620623
).values('name')
621624
self.assertCountEqual(publisher_books_qs, [{'name': 'Sams'}, {'name': 'Morgan Kaufmann'}])
625+
626+
@skipIf(connection.vendor == 'oracle', 'See https://code.djangoproject.com/ticket/31584')
627+
def test_annotation_exists_aggregate_values_chaining(self):
628+
qs = Book.objects.values('publisher').annotate(
629+
has_authors=Exists(Book.authors.through.objects.filter(book=OuterRef('pk'))),
630+
max_pubdate=Max('pubdate'),
631+
).values_list('max_pubdate', flat=True).order_by('max_pubdate')
632+
self.assertCountEqual(qs, [
633+
datetime.date(1991, 10, 15),
634+
datetime.date(2008, 3, 3),
635+
datetime.date(2008, 6, 23),
636+
datetime.date(2008, 11, 3),
637+
])

0 commit comments

Comments
 (0)