Implement __bool__ on Q and QCombination

This commit is contained in:
Filip Kucharczyk 2019-12-05 00:21:03 +01:00
parent 78b240b740
commit cb77bb6b69
3 changed files with 28 additions and 5 deletions

View File

@ -686,7 +686,7 @@ class BaseQuerySet(object):
.. versionchanged:: 0.6 Raises InvalidQueryError if filter has been set .. versionchanged:: 0.6 Raises InvalidQueryError if filter has been set
""" """
queryset = self.clone() queryset = self.clone()
if not queryset._query_obj.empty: if queryset._query_obj:
msg = "Cannot use a filter whilst using `with_id`" msg = "Cannot use a filter whilst using `with_id`"
raise InvalidQueryError(msg) raise InvalidQueryError(msg)
return queryset.filter(pk=object_id).first() return queryset.filter(pk=object_id).first()

View File

@ -2,6 +2,8 @@ import copy
from mongoengine.errors import InvalidQueryError from mongoengine.errors import InvalidQueryError
from mongoengine.queryset import transform from mongoengine.queryset import transform
import warnings
__all__ = ("Q", "QNode") __all__ = ("Q", "QNode")
@ -101,13 +103,15 @@ class QNode(object):
return self return self
# Or if this Q is empty, ignore it and just use `other`. # Or if this Q is empty, ignore it and just use `other`.
if self.empty: if not self:
return other return other
return QCombination(operation, [self, other]) return QCombination(operation, [self, other])
@property @property
def empty(self): def empty(self):
msg = "'empty' property is deprecated in favour of using 'not bool(filter)"
warnings.warn(msg, DeprecationWarning)
return False return False
def __or__(self, other): def __or__(self, other):
@ -137,6 +141,9 @@ class QCombination(QNode):
op = " & " if self.operation is self.AND else " | " op = " & " if self.operation is self.AND else " | "
return "(%s)" % op.join([repr(node) for node in self.children]) return "(%s)" % op.join([repr(node) for node in self.children])
def __bool__(self):
return bool(self.children)
def accept(self, visitor): def accept(self, visitor):
for i in range(len(self.children)): for i in range(len(self.children)):
if isinstance(self.children[i], QNode): if isinstance(self.children[i], QNode):
@ -146,6 +153,8 @@ class QCombination(QNode):
@property @property
def empty(self): def empty(self):
msg = "'empty' property is deprecated in favour of using 'not bool(filter)"
warnings.warn(msg, DeprecationWarning)
return not bool(self.children) return not bool(self.children)
def __eq__(self, other): def __eq__(self, other):
@ -167,12 +176,15 @@ class Q(QNode):
def __repr__(self): def __repr__(self):
return "Q(**%s)" % repr(self.query) return "Q(**%s)" % repr(self.query)
def __bool__(self):
return bool(self.query)
def __eq__(self, other):
return self.__class__ == other.__class__ and self.query == other.query
def accept(self, visitor): def accept(self, visitor):
return visitor.visit_query(self) return visitor.visit_query(self)
@property @property
def empty(self): def empty(self):
return not bool(self.query) return not bool(self.query)
def __eq__(self, other):
return self.__class__ == other.__class__ and self.query == other.query

View File

@ -407,6 +407,17 @@ class TestQ(unittest.TestCase):
def test_combine_or_both_empty(self): def test_combine_or_both_empty(self):
assert Q() | Q() == Q() assert Q() | Q() == Q()
def test_q_bool(self):
assert Q(name="John")
assert not Q()
def test_combine_bool(self):
assert not Q() & Q()
assert Q() & Q(name="John")
assert Q(name="John") & Q()
assert Q() | Q(name="John")
assert Q(name="John") | Q()
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()