Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Optimised use of 'in' operator on QuerySet using an explicit __contai…

…ns__ 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
  • Loading branch information...
commit eeb10d5f2c5375ec28b7761f9ea0fd4f1d2e4bd1 1 parent bb428f3
Luke Plant authored December 09, 2009
30  django/db/models/query.py
@@ -107,6 +107,36 @@ def __nonzero__(self):
107 107
             return False
108 108
         return True
109 109
 
  110
+    def __contains__(self, val):
  111
+        # The 'in' operator works without this method, due to __iter__. This
  112
+        # implementation exists only to shortcut the creation of Model
  113
+        # instances, by bailing out early if we find a matching element.
  114
+        pos = 0
  115
+        if self._result_cache is not None:
  116
+            if val in self._result_cache:
  117
+                return True
  118
+            elif self._iter is None:
  119
+                # iterator is exhausted, so we have our answer
  120
+                return False
  121
+            # remember not to check these again:
  122
+            pos = len(self._result_cache)
  123
+        else:
  124
+            # We need to start filling the result cache out. The following
  125
+            # ensures that self._iter is not None and self._result_cache is not
  126
+            # None
  127
+            it = iter(self)
  128
+
  129
+        # Carry on, one result at a time.
  130
+        while True:
  131
+            if len(self._result_cache) <= pos:
  132
+                self._fill_cache(num=1)
  133
+            if self._iter is None:
  134
+                # we ran out of items
  135
+                return False
  136
+            if self._result_cache[pos] == val:
  137
+                return True
  138
+            pos += 1
  139
+
110 140
     def __getitem__(self, k):
111 141
         """
112 142
         Retrieves an item or slice from the set of results.
8  tests/modeltests/basic/models.py
@@ -211,6 +211,14 @@ def __unicode__(self):
211 211
 >>> Article.objects.get(id__exact=8) == Article.objects.get(id__exact=7)
212 212
 False
213 213
 
  214
+# You can use 'in' to test for membership...
  215
+>>> a8 in Article.objects.all()
  216
+True
  217
+
  218
+# ... but there will often be more efficient ways if that is all you need:
  219
+>>> Article.objects.filter(id=a8.id).exists()
  220
+True
  221
+
214 222
 # dates() returns a list of available dates of the given scope for the given field.
215 223
 >>> Article.objects.dates('pub_date', 'year')
216 224
 [datetime.datetime(2005, 1, 1, 0, 0)]

0 notes on commit eeb10d5

Please sign in to comment.
Something went wrong with that request. Please try again.