summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Plant <L.Plant.98@cantab.net>2009-12-09 16:07:21 +0000
committerLuke Plant <L.Plant.98@cantab.net>2009-12-09 16:07:21 +0000
commiteeb10d5f2c5375ec28b7761f9ea0fd4f1d2e4bd1 (patch)
tree8fbe20cb1448eb57cbbbd08eddc937fc630aad1d
parentbb428f3e86953d09df050b2614639f5c8a68840d (diff)
Optimised use of 'in' operator on QuerySet using an explicit __contains__ method.
Without this change, use of 'in' on a QuerySet resulted in ._result_cache being fully populated, which sometimes is unnecessary work. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11803 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/db/models/query.py30
-rw-r--r--tests/modeltests/basic/models.py8
2 files changed, 38 insertions, 0 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 36949ac390..6a16ce1b33 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -107,6 +107,36 @@ class QuerySet(object):
return False
return True
+ def __contains__(self, val):
+ # The 'in' operator works without this method, due to __iter__. This
+ # implementation exists only to shortcut the creation of Model
+ # instances, by bailing out early if we find a matching element.
+ pos = 0
+ if self._result_cache is not None:
+ if val in self._result_cache:
+ return True
+ elif self._iter is None:
+ # iterator is exhausted, so we have our answer
+ return False
+ # remember not to check these again:
+ pos = len(self._result_cache)
+ else:
+ # We need to start filling the result cache out. The following
+ # ensures that self._iter is not None and self._result_cache is not
+ # None
+ it = iter(self)
+
+ # Carry on, one result at a time.
+ while True:
+ if len(self._result_cache) <= pos:
+ self._fill_cache(num=1)
+ if self._iter is None:
+ # we ran out of items
+ return False
+ if self._result_cache[pos] == val:
+ return True
+ pos += 1
+
def __getitem__(self, k):
"""
Retrieves an item or slice from the set of results.
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py
index 2dbde58256..34bfc6a83e 100644
--- a/tests/modeltests/basic/models.py
+++ b/tests/modeltests/basic/models.py
@@ -211,6 +211,14 @@ True
>>> Article.objects.get(id__exact=8) == Article.objects.get(id__exact=7)
False
+# You can use 'in' to test for membership...
+>>> a8 in Article.objects.all()
+True
+
+# ... but there will often be more efficient ways if that is all you need:
+>>> Article.objects.filter(id=a8.id).exists()
+True
+
# dates() returns a list of available dates of the given scope for the given field.
>>> Article.objects.dates('pub_date', 'year')
[datetime.datetime(2005, 1, 1, 0, 0)]