From e1fc07c047f8e46c2cea0120f44011fc458f1e91 Mon Sep 17 00:00:00 2001 From: Ian Foote Date: Thu, 15 Nov 2018 14:43:58 +0000 Subject: [PATCH] Fixed #17930 -- Allowed ORing (|) with sliced QuerySets. --- django/db/models/query.py | 5 ++++- tests/queries/tests.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/django/db/models/query.py b/django/db/models/query.py index 1755bea1a8..b40c768f5c 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -327,8 +327,11 @@ class QuerySet: return other if isinstance(other, EmptyQuerySet): return self - combined = self._chain() + query = self if self.query.can_filter() else self.model._base_manager.filter(pk__in=self.values('pk')) + combined = query._chain() combined._merge_known_related_objects(other) + if not other.query.can_filter(): + other = other.model._base_manager.filter(pk__in=other.values('pk')) combined.query.combine(other.query, sql.OR) return combined diff --git a/tests/queries/tests.py b/tests/queries/tests.py index 25e3b283ec..a30403a153 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -2140,6 +2140,37 @@ class SubqueryTests(TestCase): ) +@skipUnlessDBFeature('allow_sliced_subqueries_with_in') +class QuerySetBitwiseOperationTests(TestCase): + @classmethod + def setUpTestData(cls): + school = School.objects.create() + cls.room_1 = Classroom.objects.create(school=school, has_blackboard=False, name='Room 1') + cls.room_2 = Classroom.objects.create(school=school, has_blackboard=True, name='Room 2') + cls.room_3 = Classroom.objects.create(school=school, has_blackboard=True, name='Room 3') + cls.room_4 = Classroom.objects.create(school=school, has_blackboard=False, name='Room 4') + + def test_or_with_rhs_slice(self): + qs1 = Classroom.objects.filter(has_blackboard=True) + qs2 = Classroom.objects.filter(has_blackboard=False)[:1] + self.assertCountEqual(qs1 | qs2, [self.room_1, self.room_2, self.room_3]) + + def test_or_with_lhs_slice(self): + qs1 = Classroom.objects.filter(has_blackboard=True)[:1] + qs2 = Classroom.objects.filter(has_blackboard=False) + self.assertCountEqual(qs1 | qs2, [self.room_1, self.room_2, self.room_4]) + + def test_or_with_both_slice(self): + qs1 = Classroom.objects.filter(has_blackboard=False)[:1] + qs2 = Classroom.objects.filter(has_blackboard=True)[:1] + self.assertCountEqual(qs1 | qs2, [self.room_1, self.room_2]) + + def test_or_with_both_slice_and_ordering(self): + qs1 = Classroom.objects.filter(has_blackboard=False).order_by('-pk')[:1] + qs2 = Classroom.objects.filter(has_blackboard=True).order_by('-name')[:1] + self.assertCountEqual(qs1 | qs2, [self.room_3, self.room_4]) + + class CloneTests(TestCase): def test_evaluated_queryset_as_argument(self):