Author: lukeplant
Date: 2009-12-09 10:07:21 -0600 (Wed, 09 Dec 2009)
New Revision: 11803

Modified:
   django/trunk/django/db/models/query.py
   django/trunk/tests/modeltests/basic/models.py
Log:
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.



Modified: django/trunk/django/db/models/query.py
===================================================================
--- django/trunk/django/db/models/query.py      2009-12-09 12:47:50 UTC (rev 
11802)
+++ django/trunk/django/db/models/query.py      2009-12-09 16:07:21 UTC (rev 
11803)
@@ -107,6 +107,36 @@
             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.

Modified: django/trunk/tests/modeltests/basic/models.py
===================================================================
--- django/trunk/tests/modeltests/basic/models.py       2009-12-09 12:47:50 UTC 
(rev 11802)
+++ django/trunk/tests/modeltests/basic/models.py       2009-12-09 16:07:21 UTC 
(rev 11803)
@@ -211,6 +211,14 @@
 >>> 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)]

--

You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.


Reply via email to