Merge pull request #655 from jonathansp/master
Avoid to open all documents from cursors in an if stmt
This commit is contained in:
commit
2d5280fc95
2
AUTHORS
2
AUTHORS
@ -189,3 +189,5 @@ that much better:
|
|||||||
* Tom (https://github.com/tomprimozic)
|
* Tom (https://github.com/tomprimozic)
|
||||||
* j0hnsmith (https://github.com/j0hnsmith)
|
* j0hnsmith (https://github.com/j0hnsmith)
|
||||||
* Damien Churchill (https://github.com/damoxc)
|
* Damien Churchill (https://github.com/damoxc)
|
||||||
|
* Jonathan Simon Prates (https://github.com/jonathansp)
|
||||||
|
* Thiago Papageorgiou (https://github.com/tmpapageorgiou)
|
@ -50,7 +50,7 @@ class BaseQuerySet(object):
|
|||||||
self._initial_query = {}
|
self._initial_query = {}
|
||||||
self._where_clause = None
|
self._where_clause = None
|
||||||
self._loaded_fields = QueryFieldList()
|
self._loaded_fields = QueryFieldList()
|
||||||
self._ordering = []
|
self._ordering = None
|
||||||
self._snapshot = False
|
self._snapshot = False
|
||||||
self._timeout = True
|
self._timeout = True
|
||||||
self._class_check = True
|
self._class_check = True
|
||||||
@ -154,6 +154,22 @@ class BaseQuerySet(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _has_data(self):
|
||||||
|
""" Retrieves whether cursor has any data. """
|
||||||
|
|
||||||
|
queryset = self.order_by()
|
||||||
|
return False if queryset.first() is None else True
|
||||||
|
|
||||||
|
def __nonzero__(self):
|
||||||
|
""" Avoid to open all records in an if stmt in Py2. """
|
||||||
|
|
||||||
|
return self._has_data()
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
""" Avoid to open all records in an if stmt in Py3. """
|
||||||
|
|
||||||
|
return self._has_data()
|
||||||
|
|
||||||
# Core functions
|
# Core functions
|
||||||
|
|
||||||
def all(self):
|
def all(self):
|
||||||
@ -1189,8 +1205,9 @@ class BaseQuerySet(object):
|
|||||||
if self._ordering:
|
if self._ordering:
|
||||||
# Apply query ordering
|
# Apply query ordering
|
||||||
self._cursor_obj.sort(self._ordering)
|
self._cursor_obj.sort(self._ordering)
|
||||||
elif self._document._meta['ordering']:
|
elif self._ordering is None and self._document._meta['ordering']:
|
||||||
# Otherwise, apply the ordering from the document model
|
# Otherwise, apply the ordering from the document model, unless
|
||||||
|
# it's been explicitly cleared via order_by with no arguments
|
||||||
order = self._get_order_by(self._document._meta['ordering'])
|
order = self._get_order_by(self._document._meta['ordering'])
|
||||||
self._cursor_obj.sort(order)
|
self._cursor_obj.sort(order)
|
||||||
|
|
||||||
@ -1392,7 +1409,7 @@ class BaseQuerySet(object):
|
|||||||
pass
|
pass
|
||||||
key_list.append((key, direction))
|
key_list.append((key, direction))
|
||||||
|
|
||||||
if self._cursor_obj:
|
if self._cursor_obj and key_list:
|
||||||
self._cursor_obj.sort(key_list)
|
self._cursor_obj.sort(key_list)
|
||||||
return key_list
|
return key_list
|
||||||
|
|
||||||
|
@ -1040,6 +1040,76 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
expected = [blog_post_1, blog_post_2, blog_post_3]
|
expected = [blog_post_1, blog_post_2, blog_post_3]
|
||||||
self.assertSequence(qs, expected)
|
self.assertSequence(qs, expected)
|
||||||
|
|
||||||
|
def test_clear_ordering(self):
|
||||||
|
""" Make sure one can clear the query set ordering by applying a
|
||||||
|
consecutive order_by()
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
Person(name="A").save()
|
||||||
|
Person(name="B").save()
|
||||||
|
|
||||||
|
qs = Person.objects.order_by('-name')
|
||||||
|
|
||||||
|
# Make sure we can clear a previously specified ordering
|
||||||
|
with query_counter() as q:
|
||||||
|
lst = list(qs.order_by())
|
||||||
|
|
||||||
|
op = q.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertTrue('$orderby' not in op['query'])
|
||||||
|
self.assertEqual(lst[0].name, 'A')
|
||||||
|
|
||||||
|
# Make sure previously specified ordering is preserved during
|
||||||
|
# consecutive calls to the same query set
|
||||||
|
with query_counter() as q:
|
||||||
|
lst = list(qs)
|
||||||
|
|
||||||
|
op = q.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertTrue('$orderby' in op['query'])
|
||||||
|
self.assertEqual(lst[0].name, 'B')
|
||||||
|
|
||||||
|
def test_clear_default_ordering(self):
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
name = StringField()
|
||||||
|
meta = {
|
||||||
|
'ordering': ['-name']
|
||||||
|
}
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
Person(name="A").save()
|
||||||
|
Person(name="B").save()
|
||||||
|
|
||||||
|
qs = Person.objects
|
||||||
|
|
||||||
|
# Make sure clearing default ordering works
|
||||||
|
with query_counter() as q:
|
||||||
|
lst = list(qs.order_by())
|
||||||
|
|
||||||
|
op = q.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertTrue('$orderby' not in op['query'])
|
||||||
|
self.assertEqual(lst[0].name, 'A')
|
||||||
|
|
||||||
|
# Make sure default ordering is preserved during consecutive calls
|
||||||
|
# to the same query set
|
||||||
|
with query_counter() as q:
|
||||||
|
lst = list(qs)
|
||||||
|
|
||||||
|
op = q.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertTrue('$orderby' in op['query'])
|
||||||
|
self.assertEqual(lst[0].name, 'B')
|
||||||
|
|
||||||
def test_find_embedded(self):
|
def test_find_embedded(self):
|
||||||
"""Ensure that an embedded document is properly returned from a query.
|
"""Ensure that an embedded document is properly returned from a query.
|
||||||
"""
|
"""
|
||||||
@ -3814,6 +3884,111 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
self.assertEqual(Example.objects(size=instance_size).count(), 1)
|
self.assertEqual(Example.objects(size=instance_size).count(), 1)
|
||||||
self.assertEqual(Example.objects(size__in=[instance_size]).count(), 1)
|
self.assertEqual(Example.objects(size__in=[instance_size]).count(), 1)
|
||||||
|
|
||||||
|
def test_cursor_in_an_if_stmt(self):
|
||||||
|
|
||||||
|
class Test(Document):
|
||||||
|
test_field = StringField()
|
||||||
|
|
||||||
|
Test.drop_collection()
|
||||||
|
queryset = Test.objects
|
||||||
|
|
||||||
|
if queryset:
|
||||||
|
raise AssertionError('Empty cursor returns True')
|
||||||
|
|
||||||
|
test = Test()
|
||||||
|
test.test_field = 'test'
|
||||||
|
test.save()
|
||||||
|
|
||||||
|
queryset = Test.objects
|
||||||
|
if not test:
|
||||||
|
raise AssertionError('Cursor has data and returned False')
|
||||||
|
|
||||||
|
queryset.next()
|
||||||
|
if not queryset:
|
||||||
|
raise AssertionError('Cursor has data and it must returns True,'
|
||||||
|
' even in the last item.')
|
||||||
|
|
||||||
|
def test_bool_performance(self):
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
for i in xrange(100):
|
||||||
|
Person(name="No: %s" % i).save()
|
||||||
|
|
||||||
|
with query_counter() as q:
|
||||||
|
if Person.objects:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(q, 1)
|
||||||
|
op = q.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertEqual(op['nreturned'], 1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bool_with_ordering(self):
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
Person(name="Test").save()
|
||||||
|
|
||||||
|
qs = Person.objects.order_by('name')
|
||||||
|
|
||||||
|
with query_counter() as q:
|
||||||
|
|
||||||
|
if qs:
|
||||||
|
pass
|
||||||
|
|
||||||
|
op = q.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertFalse('$orderby' in op['query'],
|
||||||
|
'BaseQuerySet cannot use orderby in if stmt')
|
||||||
|
|
||||||
|
with query_counter() as p:
|
||||||
|
|
||||||
|
for x in qs:
|
||||||
|
pass
|
||||||
|
|
||||||
|
op = p.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertTrue('$orderby' in op['query'],
|
||||||
|
'BaseQuerySet cannot remove orderby in for loop')
|
||||||
|
|
||||||
|
def test_bool_with_ordering_from_meta_dict(self):
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
name = StringField()
|
||||||
|
meta = {
|
||||||
|
'ordering': ['name']
|
||||||
|
}
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
|
||||||
|
Person(name="B").save()
|
||||||
|
Person(name="C").save()
|
||||||
|
Person(name="A").save()
|
||||||
|
|
||||||
|
with query_counter() as q:
|
||||||
|
|
||||||
|
if Person.objects:
|
||||||
|
pass
|
||||||
|
|
||||||
|
op = q.db.system.profile.find({"ns":
|
||||||
|
{"$ne": "%s.system.indexes" % q.db.name}})[0]
|
||||||
|
|
||||||
|
self.assertFalse('$orderby' in op['query'],
|
||||||
|
'BaseQuerySet must remove orderby from meta in boolen test')
|
||||||
|
|
||||||
|
self.assertEqual(Person.objects.first().name, 'A')
|
||||||
|
self.assertTrue(Person.objects._has_data(),
|
||||||
|
'Cursor has data and returned False')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user