From 0debc6ba5b99027dccd287f8c247b328e4fe9483 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Thu, 18 Feb 2021 14:01:48 +0100 Subject: [PATCH] [3.2.x] Fixed #32455 -- Allowed right combining Q() with boolean expressions. Backport of f2bef2b7bc6c817af0f5fa77e1052a1f5ce12f71 from master --- django/db/models/query_utils.py | 2 +- tests/expressions/tests.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/django/db/models/query_utils.py b/django/db/models/query_utils.py index c2b693ab8db..3beca7ce301 100644 --- a/django/db/models/query_utils.py +++ b/django/db/models/query_utils.py @@ -68,7 +68,7 @@ class Q(tree.Node): super().__init__(children=[*args, *sorted(kwargs.items())], connector=_connector, negated=_negated) def _combine(self, other, conn): - if not isinstance(other, Q): + if not(isinstance(other, Q) or getattr(other, 'conditional', False) is True): raise TypeError(other) # If the other Q() is empty, ignore it and just use `self`. diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index bb8aeda8b06..1c32ab045b8 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -803,6 +803,14 @@ class BasicExpressionsTests(TestCase): Employee.objects.filter(Exists(is_poc) | Q(salary__lt=15)), [self.example_inc.ceo, self.max], ) + self.assertCountEqual( + Employee.objects.filter(Q(salary__gte=30) & Exists(is_ceo)), + [self.max], + ) + self.assertCountEqual( + Employee.objects.filter(Q(salary__lt=15) | Exists(is_poc)), + [self.example_inc.ceo, self.max], + ) def test_boolean_expression_combined_with_empty_Q(self): is_poc = Company.objects.filter(point_of_contact=OuterRef('pk')) @@ -810,7 +818,9 @@ class BasicExpressionsTests(TestCase): self.gmbh.save() tests = [ Exists(is_poc) & Q(), + Q() & Exists(is_poc), Exists(is_poc) | Q(), + Q() | Exists(is_poc), ] for conditions in tests: with self.subTest(conditions):