[1.11.x] Fixed #29286 -- Fixed column mismatch crash with QuerySet.values() or values_list() after combining an annotated and unannotated queryset with union(), difference(), or intersection().

Regression in a0c03c62a8ac586e5be5b21393c925afa581efaf.

Thanks Tim Graham and Carlton Gibson for reviews.

Backport of 0b66c3b442875627fa6daef4ac1e90900d74290b from master.
This commit is contained in:
Mariusz Felisiak 2018-04-13 12:15:52 +02:00
parent 46496a542c
commit f89b11b879
No known key found for this signature in database
GPG Key ID: 2EF56372BA48CD1B
3 changed files with 16 additions and 4 deletions

View File

@ -393,9 +393,8 @@ class SQLCompiler(object):
# If the columns list is limited, then all combined queries
# must have the same columns list. Set the selects defined on
# the query on all combined queries, if not already set.
if (not compiler.query.values_select and not compiler.query.annotations and
self.query.values_select):
compiler.query.set_values(self.query.values_select)
if not compiler.query.values_select and self.query.values_select:
compiler.query.set_values(tuple(self.query.values_select) + tuple(self.query.annotation_select))
parts += (compiler.as_sql(),)
except EmptyResultSet:
# Omit the empty queryset with UNION and with DIFFERENCE if the

View File

@ -15,3 +15,8 @@ Bugfixes
* Fixed crashes in ``django.contrib.admindocs`` when a view is a callable
object, such as ``django.contrib.syndication.views.Feed`` (:ticket:`29296`).
* Fixed a regression in Django 1.11.12 where ``QuerySet.values()`` or
``values_list()`` after combining an annotated and unannotated queryset with
``union()``, ``difference()``, or ``intersection()`` crashed due to mismatching
columns (:ticket:`29286`).

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals
from django.db.models import F, IntegerField, Value
from django.db.models import Exists, F, IntegerField, OuterRef, Value
from django.db.utils import DatabaseError
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils.six.moves import range
@ -139,6 +139,14 @@ class QuerySetSetOperationTests(TestCase):
).values_list('num', 'count')
self.assertCountEqual(qs1.union(qs2), [(1, 0), (2, 1)])
def test_union_with_values_list_on_annotated_and_unannotated(self):
ReservedName.objects.create(name='rn1', order=1)
qs1 = Number.objects.annotate(
has_reserved_name=Exists(ReservedName.objects.filter(order=OuterRef('num')))
).filter(has_reserved_name=True)
qs2 = Number.objects.filter(num=9)
self.assertCountEqual(qs1.union(qs2).values_list('num', flat=True), [1, 9])
def test_count_union(self):
qs1 = Number.objects.filter(num__lte=1).values('num')
qs2 = Number.objects.filter(num__gte=2, num__lte=3).values('num')