[1.11.x] Fixed #28293 -- Fixed union(), intersection(), and difference() when combining with an EmptyQuerySet.
Thanks Jon Dufresne for the report and Tim Graham for the review.
Backport of 82175ead72
from master
This commit is contained in:
parent
927d9b51fe
commit
44e29ea1e9
|
@ -838,12 +838,25 @@ class QuerySet(object):
|
|||
"union() received an unexpected keyword argument '%s'" %
|
||||
(unexpected_kwarg,)
|
||||
)
|
||||
# If the query is an EmptyQuerySet, combine all nonempty querysets.
|
||||
if isinstance(self, EmptyQuerySet):
|
||||
qs = [q for q in other_qs if not isinstance(q, EmptyQuerySet)]
|
||||
return qs[0]._combinator_query('union', *qs[1:], **kwargs) if qs else self
|
||||
return self._combinator_query('union', *other_qs, **kwargs)
|
||||
|
||||
def intersection(self, *other_qs):
|
||||
# If any query is an EmptyQuerySet, return it.
|
||||
if isinstance(self, EmptyQuerySet):
|
||||
return self
|
||||
for other in other_qs:
|
||||
if isinstance(other, EmptyQuerySet):
|
||||
return other
|
||||
return self._combinator_query('intersection', *other_qs)
|
||||
|
||||
def difference(self, *other_qs):
|
||||
# If the query is an EmptyQuerySet, return it.
|
||||
if isinstance(self, EmptyQuerySet):
|
||||
return self
|
||||
return self._combinator_query('difference', *other_qs)
|
||||
|
||||
def select_for_update(self, nowait=False, skip_locked=False):
|
||||
|
|
|
@ -379,7 +379,7 @@ class SQLCompiler(object):
|
|||
features = self.connection.features
|
||||
compilers = [
|
||||
query.get_compiler(self.using, self.connection)
|
||||
for query in self.query.combined_queries
|
||||
for query in self.query.combined_queries if not query.is_empty()
|
||||
]
|
||||
if not features.supports_slicing_ordering_in_compound:
|
||||
for query, compiler in zip(self.query.combined_queries, compilers):
|
||||
|
|
|
@ -29,3 +29,6 @@ Bugfixes
|
|||
|
||||
* Fixed crash in admin's inlines when a model has an inherited non-editable
|
||||
primary key (:ticket:`27967`).
|
||||
|
||||
* Fixed ``QuerySet.union()``, ``intersection()``, and ``difference()`` when
|
||||
combining with an ``EmptyQuerySet`` (:ticket:`28293`).
|
||||
|
|
|
@ -45,6 +45,31 @@ class QuerySetSetOperationTests(TestCase):
|
|||
self.assertEqual(len(list(qs1.union(qs2, all=True))), 20)
|
||||
self.assertEqual(len(list(qs1.union(qs2))), 10)
|
||||
|
||||
@skipUnlessDBFeature('supports_select_intersection')
|
||||
def test_intersection_with_empty_qs(self):
|
||||
qs1 = Number.objects.all()
|
||||
qs2 = Number.objects.none()
|
||||
self.assertEqual(len(qs1.intersection(qs2)), 0)
|
||||
self.assertEqual(len(qs2.intersection(qs1)), 0)
|
||||
self.assertEqual(len(qs2.intersection(qs2)), 0)
|
||||
|
||||
@skipUnlessDBFeature('supports_select_difference')
|
||||
def test_difference_with_empty_qs(self):
|
||||
qs1 = Number.objects.all()
|
||||
qs2 = Number.objects.none()
|
||||
self.assertEqual(len(qs1.difference(qs2)), 10)
|
||||
self.assertEqual(len(qs2.difference(qs1)), 0)
|
||||
self.assertEqual(len(qs2.difference(qs2)), 0)
|
||||
|
||||
def test_union_with_empty_qs(self):
|
||||
qs1 = Number.objects.all()
|
||||
qs2 = Number.objects.none()
|
||||
self.assertEqual(len(qs1.union(qs2)), 10)
|
||||
self.assertEqual(len(qs2.union(qs1)), 10)
|
||||
self.assertEqual(len(qs2.union(qs1, qs1, qs1)), 10)
|
||||
self.assertEqual(len(qs2.union(qs1, qs1, all=True)), 20)
|
||||
self.assertEqual(len(qs2.union(qs2)), 0)
|
||||
|
||||
def test_union_bad_kwarg(self):
|
||||
qs1 = Number.objects.all()
|
||||
msg = "union() received an unexpected keyword argument 'bad'"
|
||||
|
|
Loading…
Reference in New Issue