On Monday 30 January 2006 18:56, Luke Plant wrote:

> Actually, Q()s are immutable, so doing a deepcopy on their account
> was a complete mistake on my part.  You don't have to copy them at
> all, which would make them rather nice to use performance-wise.

In which case, and assuming there aren't other objections, the attached 
patch will restore the & and | behaviour of the QuerySets.  I'll leave 
it for your review.

Luke

-- 
"I'm at peace with the world. I'm completely serene. I know why I was 
put here and why everything exists. I am here so everybody can do what 
I want. Once everybody accepts it, they'll be serene too." (Calvin and 
Hobbes)

Luke Plant || L.Plant.98 (at) cantab.net || http://lukeplant.me.uk/
Index: django/db/models/query.py
===================================================================
--- django/db/models/query.py	(revision 2186)
+++ django/db/models/query.py	(working copy)
@@ -68,7 +68,7 @@
     klass = None
 
     def __init__(self):
-        self._filters = self.core_filters.copy()
+        self._filters = Q(**(self.core_filters))
         self._order_by = None        # Ordering, e.g. ('date', '-name'). If None, use model's ordering.
         self._select_related = False # Whether to fill cache for related objects.
         self._distinct = False       # Whether the query should use SELECT DISTINCT.
@@ -104,6 +104,16 @@
         else:
             return self._result_cache[k]
 
+    def __and__(self, other):
+        combined = self._combine(other)
+        combined._filters = self._filters & other._filters
+        return combined
+
+    def __or__(self, other):
+        combined = self._combine(other)
+        combined._filters = self._filters | other._filters
+        return combined
+
     ####################################
     # METHODS THAT DO DATABASE QUERIES #
     ####################################
@@ -245,7 +255,8 @@
     def filter(self, **kwargs):
         "Returns a new QuerySet instance with the args ANDed to the existing set."
         clone = self._clone()
-        clone._filters.update(kwargs)
+        if len(kwargs) > 0:
+            clone._filters = clone._filters & Q(**kwargs)
         return clone
 
     def select_related(self, true_or_false=True):
@@ -275,7 +286,7 @@
     def _clone(self, **kwargs):
         c = QuerySet()
         c.klass = self.klass
-        c._filters = self._filters.copy()
+        c._filters = self._filters
         c._order_by = self._order_by
         c._select_related = self._select_related
         c._distinct = self._distinct
@@ -288,6 +299,19 @@
         c.__dict__.update(kwargs)
         return c
 
+    def _combine(self, other):
+        if self._distinct != other._distinct:
+            raise ValueException, "Can't combine a unique query with a non-unique query"
+        #  use 'other's order by
+        #  (so that A.filter(args1) & A.filter(args2) does the same as
+        #   A.filter(args1).filter(args2)
+        combined = other._clone()
+        # If 'self' is ordered and 'other' isn't, propagate 'self's ordering
+        if (self._order_by is not None and len(self._order_by) > 0) and \
+           (combined._order_by is None or len(combined._order_by == 0)):
+            combined._order_by = self._order_by
+        return combined
+
     def _get_data(self):
         return list(self.iterator())
 #         if self._result_cache is None:
@@ -305,7 +329,7 @@
         params = self._params[:]
 
         # Convert self._filters into SQL.
-        tables2, joins2, where2, params2 = parse_lookup(self._filters.items(), opts)
+        tables2, joins2, where2, params2 = self._filters.get_sql(opts)
         tables.extend(tables2)
         joins.update(joins2)
         where.extend(where2)
@@ -377,32 +401,6 @@
 
         return select, " ".join(sql), params
 
-# class QuerySet(object):
-#     def _ensure_compatible(self, other):
-#         if self._distinct != other._distinct:
-#             raise ValueException, "Can't combine a unique query with a non-unique query"
-#
-#     def _combine(self, other):
-#         self._ensure_compatible(other)
-#         # get a deepcopy of 'other's order by
-#         #  (so that A.filter(args1) & A.filter(args2) does the same as
-#         #   A.filter(args1).filter(args2)
-#         combined = other._clone()
-#         # If 'self' is ordered and 'other' isn't, propagate 'self's ordering
-#         if len(self._order_by) > 0 and len(combined._order_by == 0):
-#             combined._order_by = copy.deepcopy(self._order_by)
-#         return combined
-#
-#     def __and__(self, other):
-#         combined = self._combine(other)
-#         combined._filter = self._filter & other._filter
-#         return combined
-#
-#     def __or__(self, other):
-#         combined = self._combine(other)
-#         combined._filter = self._filter | other._filter
-#         return combined
-
 class QOperator:
     "Base class for QAnd and QOr"
     def __init__(self, *args):

Reply via email to