exec_js functions now acknowledge Q objects
This commit is contained in:
parent
21b7d8f8ea
commit
470e08f616
@ -1,6 +1,6 @@
|
||||
include README.rst
|
||||
include LICENSE
|
||||
recursive-include docs *
|
||||
prune docs/_build/*
|
||||
prune docs/_build
|
||||
recursive-include tests *
|
||||
recursive-exclude * *.pyc *.swp
|
||||
|
@ -142,8 +142,8 @@ A :class:`~mongoengine.queryset.Q` object represents part of a query, and
|
||||
can be initialised using the same keyword-argument syntax you use to query
|
||||
documents. To build a complex query, you may combine
|
||||
:class:`~mongoengine.queryset.Q` objects using the ``&`` (and) and ``|`` (or)
|
||||
operators. To use :class:`~mongoengine.queryset.Q` objects, pass them in
|
||||
as positional arguments to :attr:`Document.objects` when you filter it by
|
||||
operators. To use a :class:`~mongoengine.queryset.Q` object, pass it in as the
|
||||
first positional argument to :attr:`Document.objects` when you filter it by
|
||||
calling it with keyword arguments::
|
||||
|
||||
# Get published posts
|
||||
|
@ -111,7 +111,7 @@ class QuerySet(object):
|
||||
self._collection_obj = collection
|
||||
self._accessed_collection = False
|
||||
self._query = {}
|
||||
self._where_clauses = []
|
||||
self._where_clause = None
|
||||
|
||||
# If inheritance is allowed, only return instances and instances of
|
||||
# subclasses of the class being used
|
||||
@ -165,16 +165,18 @@ class QuerySet(object):
|
||||
|
||||
return index_list
|
||||
|
||||
def __call__(self, *q_objs, **query):
|
||||
def __call__(self, q_obj=None, **query):
|
||||
"""Filter the selected documents by calling the
|
||||
:class:`~mongoengine.queryset.QuerySet` with a query.
|
||||
|
||||
:param q_objs: :class:`~mongoengine.queryset.Q` objects to be used in
|
||||
the query
|
||||
:param q_obj: a :class:`~mongoengine.queryset.Q` object to be used in
|
||||
the query; the :class:`~mongoengine.queryset.QuerySet` is filtered
|
||||
multiple times with different :class:`~mongoengine.queryset.Q`
|
||||
objects, only the last one will be used
|
||||
:param query: Django-style query keyword arguments
|
||||
"""
|
||||
for q in q_objs:
|
||||
self._where_clauses.append(q.as_js(self._document))
|
||||
if q_obj:
|
||||
self._where_clause = q_obj.as_js(self._document)
|
||||
query = QuerySet._transform_query(_doc_cls=self._document, **query)
|
||||
self._query.update(query)
|
||||
return self
|
||||
@ -209,11 +211,11 @@ class QuerySet(object):
|
||||
|
||||
@property
|
||||
def _cursor(self):
|
||||
if not self._cursor_obj:
|
||||
if self._cursor_obj is None:
|
||||
self._cursor_obj = self._collection.find(self._query)
|
||||
# Apply where clauses to cursor
|
||||
for js in self._where_clauses:
|
||||
self._cursor_obj.where(js)
|
||||
if self._where_clause:
|
||||
self._cursor_obj.where(self._where_clause)
|
||||
|
||||
# apply default ordering
|
||||
if self._document._meta['ordering']:
|
||||
@ -516,11 +518,17 @@ class QuerySet(object):
|
||||
fields = [QuerySet._translate_field_name(self._document, f)
|
||||
for f in fields]
|
||||
collection = self._document._meta['collection']
|
||||
|
||||
scope = {
|
||||
'collection': collection,
|
||||
'query': self._query,
|
||||
'options': options or {},
|
||||
}
|
||||
|
||||
query = self._query
|
||||
if self._where_clause:
|
||||
query['$where'] = self._where_clause
|
||||
|
||||
scope['query'] = query
|
||||
code = pymongo.code.Code(code, scope=scope)
|
||||
|
||||
db = _get_db()
|
||||
|
@ -240,7 +240,7 @@ class DocumentTest(unittest.TestCase):
|
||||
|
||||
info = BlogPost.objects._collection.index_information()
|
||||
# _id, types, '-date', 'tags', ('cat', 'date')
|
||||
self.assertEqual(len(info), 5)
|
||||
self.assertEqual(len(info), 5)
|
||||
|
||||
# Indexes are lazy so use list() to perform query
|
||||
list(BlogPost.objects)
|
||||
|
@ -264,6 +264,50 @@ class QuerySetTest(unittest.TestCase):
|
||||
|
||||
BlogPost.drop_collection()
|
||||
|
||||
def test_exec_js_query(self):
|
||||
"""Ensure that queries are properly formed for use in exec_js.
|
||||
"""
|
||||
class BlogPost(Document):
|
||||
hits = IntField()
|
||||
published = BooleanField()
|
||||
|
||||
BlogPost.drop_collection()
|
||||
|
||||
post1 = BlogPost(hits=1, published=False)
|
||||
post1.save()
|
||||
|
||||
post2 = BlogPost(hits=1, published=True)
|
||||
post2.save()
|
||||
|
||||
post3 = BlogPost(hits=1, published=True)
|
||||
post3.save()
|
||||
|
||||
js_func = """
|
||||
function(hitsField) {
|
||||
var count = 0;
|
||||
db[collection].find(query).forEach(function(doc) {
|
||||
count += doc[hitsField];
|
||||
});
|
||||
return count;
|
||||
}
|
||||
"""
|
||||
|
||||
# Ensure that normal queries work
|
||||
c = BlogPost.objects(published=True).exec_js(js_func, 'hits')
|
||||
self.assertEqual(c, 2)
|
||||
|
||||
c = BlogPost.objects(published=False).exec_js(js_func, 'hits')
|
||||
self.assertEqual(c, 1)
|
||||
|
||||
# Ensure that Q object queries work
|
||||
c = BlogPost.objects(Q(published=True)).exec_js(js_func, 'hits')
|
||||
self.assertEqual(c, 2)
|
||||
|
||||
c = BlogPost.objects(Q(published=False)).exec_js(js_func, 'hits')
|
||||
self.assertEqual(c, 1)
|
||||
|
||||
BlogPost.drop_collection()
|
||||
|
||||
def test_delete(self):
|
||||
"""Ensure that documents are properly deleted from the database.
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user