#32455 closed Bug (fixed)
Q(...) & Exists(...) raises a TypeError
| Reported by: | john-parton | Owned by: | Hasan Ramezani |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 3.1 |
| Severity: | Normal | Keywords: | |
| Cc: | Matthew Schinckel | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Exists(...) & Q(...) works, but Q(...) & Exists(...) raise a TypeError
Here's a minimal example:
In [3]: Exists(Product.objects.all()) & Q()
Out[3]: <Q: (AND: <django.db.models.expressions.Exists object at 0x7fc18dd0ed90>, (AND: ))>
In [4]: Q() & Exists(Product.objects.all())
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-4-21d3dea0fcb9> in <module>
----> 1 Q() & Exists(Product.objects.all())
~/Code/venv/ecom/lib/python3.8/site-packages/django/db/models/query_utils.py in __and__(self, other)
90
91 def __and__(self, other):
---> 92 return self._combine(other, self.AND)
93
94 def __invert__(self):
~/Code/venv/ecom/lib/python3.8/site-packages/django/db/models/query_utils.py in _combine(self, other, conn)
71 def _combine(self, other, conn):
72 if not isinstance(other, Q):
---> 73 raise TypeError(other)
74
75 # If the other Q() is empty, ignore it and just use `self`.
TypeError: <django.db.models.expressions.Exists object at 0x7fc18dd21400>
The & (and |) operators should be commutative on Q-Exists pairs, but it's not
I think there's a missing definition of __rand__ somewhere.
Change History (9)
comment:1 by , 5 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:2 by , 5 years ago
| Summary: | Exists(...) & Q(...) works, but Q(...) & Exists(...) raise a TypeError → Q(...) & Exists(...) raises a TypeError |
|---|
Tests:
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
index 08ea0a51d3..20d0404f44 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -815,6 +815,15 @@ 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],
+ )
+
class IterableLookupInnerExpressionsTests(TestCase):
comment:3 by , 5 years ago
| Cc: | added |
|---|
comment:5 by , 5 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Note:
See TracTickets
for help on using tickets.
Reproduced on 3.1.6. The exception is raised by this two lines in the
Q._combine, which are not present in theCombinable._combinefrom whichExistsinherit.if not isinstance(other, Q): raise TypeError(other)