From 6efd6faa3f5a467012fa4ee128889104ca0ba6f7 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Tue, 30 Jul 2013 10:30:16 +0000 Subject: [PATCH] Fixed QuerySetNoCache.count() caching (#410) --- docs/changelog.rst | 1 + mongoengine/queryset/base.py | 10 ++-------- mongoengine/queryset/queryset.py | 15 +++++++++++++++ tests/queryset/queryset.py | 21 +++++++++++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 9112b2b8..e2f07bc0 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,7 @@ Changelog Changes in 0.8.4 ================ +- Fixed QuerySetNoCache.count() caching (#410) - Don't follow references in _get_changed_fields (#422, #417) - Allow args and kwargs to be passed through to_json (#420) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index e88feb30..a6ba49b2 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -60,7 +60,6 @@ class BaseQuerySet(object): self._none = False self._as_pymongo = False self._as_pymongo_coerce = False - self._len = None # If inheritance is allowed, only return instances and instances of # subclasses of the class being used @@ -331,14 +330,9 @@ class BaseQuerySet(object): :meth:`skip` that has been applied to this cursor into account when getting the count """ - if self._limit == 0: + if self._limit == 0 and with_limit_and_skip: return 0 - if with_limit_and_skip and self._len is not None: - return self._len - count = self._cursor.count(with_limit_and_skip=with_limit_and_skip) - if with_limit_and_skip: - self._len = count - return count + return self._cursor.count(with_limit_and_skip=with_limit_and_skip) def delete(self, write_concern=None, _from_doc_delete=False): """Delete the documents matched by the query. diff --git a/mongoengine/queryset/queryset.py b/mongoengine/queryset/queryset.py index 9cfb1b6f..1437e76b 100644 --- a/mongoengine/queryset/queryset.py +++ b/mongoengine/queryset/queryset.py @@ -94,6 +94,21 @@ class QuerySet(BaseQuerySet): except StopIteration: self._has_more = False + def count(self, with_limit_and_skip=True): + """Count the selected elements in the query. + + :param with_limit_and_skip (optional): take any :meth:`limit` or + :meth:`skip` that has been applied to this cursor into account when + getting the count + """ + if with_limit_and_skip is False: + return super(QuerySet, self).count(with_limit_and_skip) + + if self._len is None: + self._len = super(QuerySet, self).count(with_limit_and_skip) + + return self._len + def no_cache(self): """Convert to a non_caching queryset diff --git a/tests/queryset/queryset.py b/tests/queryset/queryset.py index 0ec41fac..9c04c0be 100644 --- a/tests/queryset/queryset.py +++ b/tests/queryset/queryset.py @@ -3483,6 +3483,27 @@ class QuerySetTest(unittest.TestCase): people.count() # count is cached self.assertEqual(q, 1) + def test_no_cached_queryset(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: + self.assertEqual(q, 0) + people = Person.objects.no_cache() + + [x for x in people] + self.assertEqual(q, 1) + + list(people) + self.assertEqual(q, 2) + + people.count() + self.assertEqual(q, 3) + def test_cache_not_cloned(self): class User(Document):