Add Range operator to queryset #433

Open
wants to merge 2 commits into
from
View
1 docs/guide/querying.rst
@@ -64,6 +64,7 @@ Available operators are as follows:
* ``all`` -- every item in list of values provided is in array
* ``size`` -- the size of the array is
* ``exists`` -- value for field exists
+* ``range`` -- in a range of two values (a list or tuple of two values should be provided)
The following operators are available as shortcuts to querying with regular
expressions:
View
10 mongoengine/queryset.py
@@ -619,7 +619,7 @@ def _transform_query(cls, _doc_cls=None, _field_operation=False, **query):
"""Transform a query from Django-style format to Mongo format.
"""
operators = ['ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'mod',
- 'all', 'size', 'exists', 'not']
+ 'all', 'size', 'exists', 'not', 'range']
geo_operators = ['within_distance', 'within_spherical_distance', 'within_box', 'within_polygon', 'near', 'near_sphere']
match_operators = ['contains', 'icontains', 'startswith',
'istartswith', 'endswith', 'iendswith',
@@ -674,9 +674,15 @@ def _transform_query(cls, _doc_cls=None, _field_operation=False, **query):
value = field
else:
value = field.prepare_query_value(op, value)
- elif op in ('in', 'nin', 'all', 'near'):
+ elif op in ('in', 'nin', 'all', 'near', 'range'):
# 'in', 'nin' and 'all' require a list of values
value = [field.prepare_query_value(op, v) for v in value]
+ if op == 'range':
+ op = False
+ value.sort()
+ min_val = value[0]
+ max_val = value[1]
+ value = {'$gte': min_val, '$lte': max_val}
# if op and op not in match_operators:
if op:
View
14 tests/queryset.py
@@ -678,6 +678,20 @@ def test_not(self):
obj = self.Person.objects(name__not__iexact='alice').first()
self.assertEqual(obj, None)
+ def test_range(self):
+ """Ensure that the __range operator works as expected.
+ """
+ self.Person.drop_collection()
+ walker = self.Person(name='Walker', age=50)
+ walker.save()
+ hugo = self.Person(name='Hugo', age=20)
+ hugo.save()
+ sheldon = self.Person(name='Sheldon', age=38)
+ sheldon.save()
+
+ obj = self.Person.objects(age__range=(20,40))
+ self.assertEqual(obj.count(), 2)
+
def test_filter_chaining(self):
"""Ensure filters can be chained together.
"""