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 a0c03c62a8.

Thanks Tim Graham and Carlton Gibson for reviews.
This commit is contained in:
Mariusz Felisiak 2018-04-13 12:15:52 +02:00 committed by GitHub
parent e1f13f1551
commit 0b66c3b442
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 4 deletions

View File

@ -408,9 +408,8 @@ class SQLCompiler:
# If the columns list is limited, then all combined queries # If the columns list is limited, then all combined queries
# must have the same columns list. Set the selects defined on # must have the same columns list. Set the selects defined on
# the query on all combined queries, if not already set. # the query on all combined queries, if not already set.
if (not compiler.query.values_select and not compiler.query.annotations and if not compiler.query.values_select and self.query.values_select:
self.query.values_select): compiler.query.set_values((*self.query.values_select, *self.query.annotation_select))
compiler.query.set_values(self.query.values_select)
parts += (compiler.as_sql(),) parts += (compiler.as_sql(),)
except EmptyResultSet: except EmptyResultSet:
# Omit the empty queryset with UNION and with DIFFERENCE if the # 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 * Fixed crashes in ``django.contrib.admindocs`` when a view is a callable
object, such as ``django.contrib.syndication.views.Feed`` (:ticket:`29296`). 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

@ -18,3 +18,8 @@ Bugfixes
* Fixed crashes in ``django.contrib.admindocs`` when a view is a callable * Fixed crashes in ``django.contrib.admindocs`` when a view is a callable
object, such as ``django.contrib.syndication.views.Feed`` (:ticket:`29296`). 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,4 +1,4 @@
from django.db.models import F, IntegerField, Value from django.db.models import Exists, F, IntegerField, OuterRef, Value
from django.db.utils import DatabaseError, NotSupportedError from django.db.utils import DatabaseError, NotSupportedError
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
@ -130,6 +130,14 @@ class QuerySetSetOperationTests(TestCase):
).values_list('num', 'count') ).values_list('num', 'count')
self.assertCountEqual(qs1.union(qs2), [(1, 0), (2, 1)]) 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): 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')