[3.2.x] Fixed #32627 -- Fixed QuerySet.values()/values_list() crash on combined querysets ordered by unannotated columns.

Backport of 9760e262f8 from main
This commit is contained in:
Iuri de Silvio 2021-04-08 16:31:45 -03:00 committed by Mariusz Felisiak
parent 98db3c76fc
commit b245845575
3 changed files with 34 additions and 5 deletions

View File

@ -346,10 +346,16 @@ class SQLCompiler:
continue continue
if not self.query.extra or col not in self.query.extra: if not self.query.extra or col not in self.query.extra:
if self.query.combinator and self.select:
# Don't use the first model's field because other
# combinated queries might define it differently.
order_by.append((OrderBy(F(col), descending=descending), False))
else:
# 'col' is of the form 'field' or 'field1__field2' or # 'col' is of the form 'field' or 'field1__field2' or
# '-field1__field2__field', etc. # '-field1__field2__field', etc.
order_by.extend(self.find_ordering_name( order_by.extend(self.find_ordering_name(
field, self.query.get_meta(), default_order=asc)) field, self.query.get_meta(), default_order=asc,
))
else: else:
if col not in self.query.extra_select: if col not in self.query.extra_select:
order_by.append(( order_by.append((

View File

@ -14,3 +14,8 @@ Bugfixes
* Fixed a bug in Django 3.2 where subclasses of ``BigAutoField`` and * Fixed a bug in Django 3.2 where subclasses of ``BigAutoField`` and
``SmallAutoField`` were not allowed for the :setting:`DEFAULT_AUTO_FIELD` ``SmallAutoField`` were not allowed for the :setting:`DEFAULT_AUTO_FIELD`
setting (:ticket:`32620`). setting (:ticket:`32620`).
* Fixed a regression in Django 3.2 that caused a crash of
``QuerySet.values()/values_list()`` after ``QuerySet.union()``,
``intersection()``, and ``difference()`` when it was ordered by an
unannotated field (:ticket:`32627`).

View File

@ -5,7 +5,7 @@ from django.db.models import Exists, F, IntegerField, OuterRef, Value
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.test.utils import CaptureQueriesContext from django.test.utils import CaptureQueriesContext
from .models import Number, ReservedName from .models import Celebrity, Number, ReservedName
@skipUnlessDBFeature('supports_select_union') @skipUnlessDBFeature('supports_select_union')
@ -234,6 +234,24 @@ class QuerySetSetOperationTests(TestCase):
operator.itemgetter('num'), operator.itemgetter('num'),
) )
def test_union_multiple_models_with_values_list_and_order(self):
reserved_name = ReservedName.objects.create(name='rn1', order=0)
qs1 = Celebrity.objects.all()
qs2 = ReservedName.objects.all()
self.assertSequenceEqual(
qs1.union(qs2).order_by('name').values_list('pk', flat=True),
[reserved_name.pk],
)
def test_union_multiple_models_with_values_list_and_order_by_extra_select(self):
reserved_name = ReservedName.objects.create(name='rn1', order=0)
qs1 = Celebrity.objects.extra(select={'extra_name': 'name'})
qs2 = ReservedName.objects.extra(select={'extra_name': 'name'})
self.assertSequenceEqual(
qs1.union(qs2).order_by('extra_name').values_list('pk', flat=True),
[reserved_name.pk],
)
def test_count_union(self): def test_count_union(self):
qs1 = Number.objects.filter(num__lte=1).values('num') qs1 = Number.objects.filter(num__lte=1).values('num')
qs2 = Number.objects.filter(num__gte=2, num__lte=3).values('num') qs2 = Number.objects.filter(num__gte=2, num__lte=3).values('num')