On Monday 13 February 2006 18:52, Luke Plant wrote:

> And there isn't a technical reason for it either - it should be
> relatively easy to make it go away.

The attached patch does so - the .all() call is now optional on related 
objects (it's still there due to inheritance, but I've fixed it so it 
does the right thing).  The patch is probably pretty rough, but it 
passes all the tests that were passing before (i.e. all but 4), and 
I've removed all (or almost all I think) instances of .all() on related 
objects in the tests.  I don't have any more time to work on this 
though!

Luke

-- 
Life is complex. It has both real and imaginary components. 

Luke Plant || L.Plant.98 (at) cantab.net || http://lukeplant.me.uk/
Index: django/db/models/fields/related.py
===================================================================
--- django/db/models/fields/related.py	(revision 2306)
+++ django/db/models/fields/related.py	(working copy)
@@ -7,6 +7,7 @@
 from django.core import validators
 from django import forms
 from django.dispatch import dispatcher
+from django.db.models.query import QuerySet, Q
 
 # For Python 2.3
 if not hasattr(__builtins__, 'set'):
@@ -176,6 +177,10 @@
         [this_pk_val])
     connection.commit()
 
+class RelatedManagerQuerySet(QuerySet):
+    def all(self):
+        return self._clone()
+
 class ManyRelatedObjectsDescriptor(object):
     # This class provides the functionality that makes the related-object
     # managers available as attributes on a model class, for fields that have
@@ -204,46 +209,53 @@
             rel_col_name = rel_opts.object_name.lower() + '_id'
 
         # Dynamically create a class that subclasses the related
-        # model's default manager.
+        # model's default manager and a QuerySet
         superclass = self.related.model._default_manager.__class__
 
-        class RelatedManager(superclass):
-            def get_query_set(self):
-                return superclass.get_query_set(self).filter(**(self.core_filters))
+        class RelatedManager(RelatedManagerQuerySet, superclass):
             if rel_type == "o2m":
                 def add(self, **kwargs):
                     kwargs.update({rel_field.name: instance})
+                    self._result_cache = None
                     return superclass.add(self, **kwargs)
             else:
                 def add(self, *objs, **kwargs):
+                    self._result_cache = None
                     _add_m2m_items(self, superclass, rel_model, join_table, this_col_name,
                         rel_col_name, instance._get_pk_val(), *objs, **kwargs)
             add.alters_data = True
 
             if rel_type == "o2m":
                 def remove(self, *objs):
+                    self._result_cache = None
                     pass # TODO
             else:
                 def remove(self, *objs):
+                    self._result_cache = None
                     _remove_m2m_items(rel_model, join_table, this_col_name,
                         rel_col_name, instance._get_pk_val(), *objs)
             remove.alters_data = True
 
             if rel_type == "o2m":
                 def clear(self):
+                    self._result_cache = None
                     pass # TODO
             else:
                 def clear(self):
+                    self._result_cache = None
                     _clear_m2m_items(join_table, this_col_name, instance._get_pk_val())
             clear.alters_data = True
 
+            if self.rel_type == 'o2m':
+                core_filters = {'%s__%s__exact' % (rel_field.name, rel_field.rel.to._meta.pk.name): getattr(instance, rel_field.rel.get_related_field().attname)}
+            else:
+                core_filters = {'%s__%s__exact' % (rel_field.name, instance_type._meta.pk.name): instance._get_pk_val()}
+                
+            def __init__(self, model=None):
+                QuerySet.__init__(self, model)
+                self._filters = Q(**self.core_filters)
+
         manager = RelatedManager()
-
-        if self.rel_type == 'o2m':
-            manager.core_filters = {'%s__%s__exact' % (rel_field.name, rel_field.rel.to._meta.pk.name): getattr(instance, rel_field.rel.get_related_field().attname)}
-        else:
-            manager.core_filters = {'%s__%s__exact' % (rel_field.name, instance_type._meta.pk.name): instance._get_pk_val()}
-
         manager.model = self.related.model
 
         return manager
@@ -275,27 +287,30 @@
         # model's default manager.
         superclass = self.rel_model._default_manager.__class__
 
-        class RelatedManager(superclass):
-            def get_query_set(self):
-                return superclass.get_query_set(self).extra(
-                    tables=(join_table,),
-                    where=[
+        class RelatedManager(RelatedManagerQuerySet, superclass):
+            def __init__(self, model=None):
+                QuerySet.__init__(self, model)
+                self._tables = (join_table,)
+                self._where=[
                         '%s.%s = %s.%s' % (qn(rel_opts.db_table), qn(rel_opts.pk.column), join_table, rel_col_name),
                         '%s.%s = %%s' % (join_table, this_col_name)
-                    ],
-                    params = [instance._get_pk_val()]
-                )
+                ]
+                self._params = [instance._get_pk_val()]
+
             def add(self, *objs, **kwargs):
+                self._result_cache = None
                 _add_m2m_items(self, superclass, rel_model, join_table, this_col_name,
                     rel_col_name, instance._get_pk_val(), *objs, **kwargs)
             add.alters_data = True
 
             def remove(self, *objs):
+                self._result_cache = None
                 _remove_m2m_items(rel_model, join_table, this_col_name,
                     rel_col_name, instance._get_pk_val(), *objs)
             remove.alters_data = True
 
             def clear(self):
+                self._result_cache = None
                 _clear_m2m_items(join_table, this_col_name, instance._get_pk_val())
             clear.alters_data = True
 
Index: tests/modeltests/m2o_recursive/models.py
===================================================================
--- tests/modeltests/m2o_recursive/models.py	(revision 2306)
+++ tests/modeltests/m2o_recursive/models.py	(working copy)
@@ -26,7 +26,7 @@
 >>> c = Category(id=None, name='Child category', parent=r)
 >>> c.save()
 
->>> r.child_set.all()
+>>> r.child_set
 [Child category]
 >>> r.child_set.get(name__startswith='Child')
 Child category
@@ -35,7 +35,7 @@
     ...
 DoesNotExist
 
->>> c.child_set.all()
+>>> c.child_set
 []
 >>> c.parent
 Root category
Index: tests/modeltests/many_to_many/models.py
===================================================================
--- tests/modeltests/many_to_many/models.py	(revision 2306)
+++ tests/modeltests/many_to_many/models.py	(working copy)
@@ -51,17 +51,17 @@
 >>> a2.publications.add(title='Highlights for Children')
 
 # Article objects have access to their related Publication objects.
->>> a1.publications.all()
+>>> a1.publications
 [The Python Journal]
->>> a2.publications.all()
+>>> a2.publications
 [The Python Journal, Science News, Science Weekly, Highlights for Children]
 
 # Publication objects have access to their related Article objects.
->>> p2.article_set.all()
+>>> p2.article_set
 [NASA uses Python]
 >>> p1.article_set.order_by('headline')
 [Django lets you build Web apps easily, NASA uses Python]
->>> Publication.objects.get(id=4).article_set.all()
+>>> Publication.objects.get(id=4).article_set
 [NASA uses Python]
 
 # We can perform kwarg queries across m2m relationships
@@ -111,31 +111,31 @@
 >>> a4 = Article(headline='NASA finds intelligent life on Earth')
 >>> a4.save()
 >>> p2.article_set.add(a4)
->>> p2.article_set.all()
+>>> p2.article_set
 [NASA finds intelligent life on Earth]
->>> a4.publications.all()
+>>> a4.publications
 [Science News]
 
 # Adding via the other end using keywords
 >>> p2.article_set.add(headline='Oxygen-free diet works wonders')
->>> p2.article_set.all().order_by('headline')
+>>> p2.article_set.order_by('headline')
 [NASA finds intelligent life on Earth, Oxygen-free diet works wonders]
->>> a5 = p2.article_set.all().order_by('headline')[1]
->>> a5.publications.all()
+>>> a5 = p2.article_set.order_by('headline')[1]
+>>> a5.publications
 [Science News]
 
 # Removing publication from an article:
 >>> a4.publications.remove(p2)
->>> p2.article_set.all().order_by('headline')
+>>> p2.article_set.order_by('headline')
 [Oxygen-free diet works wonders]
->>> a4.publications.all()
+>>> a4.publications
 []
 
 # And from the other end
 >>> p2.article_set.remove(a5)
 >>> p2.article_set.order_by('headline')
 []
->>> a5.publications.all()
+>>> a5.publications
 []
 
 # You can clear the whole lot:
@@ -145,21 +145,21 @@
 >>> a4.publications.order_by('title')
 [Science News, Science Weekly]
 >>> p2.article_set.clear()
->>> p2.article_set.all()
+>>> p2.article_set
 []
->>> a4.publications.all()
+>>> a4.publications
 [Science Weekly]
 
 # And you can clear from the other end
 >>> p2.article_set.add(a4, a5)
->>> p2.article_set.all().order_by('headline')
+>>> p2.article_set.order_by('headline')
 [NASA finds intelligent life on Earth, Oxygen-free diet works wonders]
 >>> a4.publications.order_by('title')
 [Science News, Science Weekly]
 >>> a4.publications.clear()
->>> a4.publications.all()
+>>> a4.publications
 []
->>> p2.article_set.all().order_by('headline')
+>>> p2.article_set.order_by('headline')
 [Oxygen-free diet works wonders]
 
 
Index: tests/modeltests/custom_pk/models.py
===================================================================
--- tests/modeltests/custom_pk/models.py	(revision 2306)
+++ tests/modeltests/custom_pk/models.py	(working copy)
@@ -62,9 +62,9 @@
 >>> b = Business(name='Sears')
 >>> b.save()
 >>> b.employees.add(dan, fran)
->>> b.employees.all()
+>>> b.employees
 [Dan Jones, Fran Jones]
->>> fran.business_set.all()
+>>> fran.business_set
 [Sears]
 >>> Business.objects.in_bulk(['Sears'])
 {'Sears': Sears}
Index: tests/modeltests/m2o_recursive2/models.py
===================================================================
--- tests/modeltests/m2o_recursive2/models.py	(revision 2306)
+++ tests/modeltests/m2o_recursive2/models.py	(working copy)
@@ -32,12 +32,12 @@
 Jane Smith
 >>> kid.father
 John Smith Senior
->>> dad.fathers_child_set.all()
+>>> dad.fathers_child_set
 [John Smith Junior]
->>> mom.mothers_child_set.all()
+>>> mom.mothers_child_set
 [John Smith Junior]
->>> kid.mothers_child_set.all()
+>>> kid.mothers_child_set
 []
->>> kid.fathers_child_set.all()
+>>> kid.fathers_child_set
 []
 """
Index: tests/modeltests/m2m_multiple/models.py
===================================================================
--- tests/modeltests/m2m_multiple/models.py	(revision 2306)
+++ tests/modeltests/m2m_multiple/models.py	(working copy)
@@ -50,30 +50,30 @@
 >>> a2.primary_categories.add(c1, c2)
 >>> a2.secondary_categories.add(c4)
 
->>> a1.primary_categories.all()
+>>> a1.primary_categories
 [Crime, News]
 
->>> a2.primary_categories.all()
+>>> a2.primary_categories
 [News, Sports]
 
->>> a1.secondary_categories.all()
+>>> a1.secondary_categories
 [Life]
 
 
->>> c1.primary_article_set.all()
+>>> c1.primary_article_set
 [Area man runs]
->>> c1.secondary_article_set.all()
+>>> c1.secondary_article_set
 []
->>> c2.primary_article_set.all()
+>>> c2.primary_article_set
 [Area man steals, Area man runs]
->>> c2.secondary_article_set.all()
+>>> c2.secondary_article_set
 []
->>> c3.primary_article_set.all()
+>>> c3.primary_article_set
 [Area man steals]
->>> c3.secondary_article_set.all()
+>>> c3.secondary_article_set
 []
->>> c4.primary_article_set.all()
+>>> c4.primary_article_set
 []
->>> c4.secondary_article_set.all()
+>>> c4.secondary_article_set
 [Area man steals, Area man runs]
 """
Index: tests/modeltests/m2m_intermediary/models.py
===================================================================
--- tests/modeltests/m2m_intermediary/models.py	(revision 2306)
+++ tests/modeltests/m2m_intermediary/models.py	(working copy)
@@ -63,6 +63,6 @@
 This is a test
 >>> w2.article
 This is a test
->>> r1.writer_set.all()
+>>> r1.writer_set
 [John Smith (Main writer)]
 """

Reply via email to