Commits

Ryan Kaskel committed 64b23be

Add convenience method to PassThroughManager.

  • Participants
  • Parent commits 7ece844

Comments (0)

Files changed (4)

    fly, which broke pickling of those querysets. For this reason,
    ``PassThroughManager`` is recommended instead.
 
+If you would like your custom ``QuerySet`` methods available through related
+managers, use the convenience ``PassThroughManager.for_queryset_class``. For
+example::
+
+    class Post(models.Model):
+        user = models.ForeignKey(User)
+        published = models.DateTimeField()
+
+        objects = PassThroughManager.for_queryset_class(PostQuerySet)()
+
+Now you will be able to make queries like::
+
+    >>> u = User.objects.all()[0]
+    >>> a.post_set.published()

File model_utils/managers.py

             return self._queryset_cls(**kargs)
         return super(PassThroughManager, self).get_query_set()
 
+    @classmethod
+    def for_queryset_class(cls, queryset_cls):
+        class _PassThroughManager(cls):
+            def get_query_set(self):
+                kwargs = {}
+                if hasattr(self, "_db"):
+                    kwargs["using"] = self._db
+                return queryset_cls(self.model, **kwargs)
+
+        return _PassThroughManager
+
 
 def manager_from(*mixins, **kwds):
     """

File model_utils/tests/models.py

 
     objects = PassThroughManager(DudeQuerySet)
     abiders = AbidingManager()
+
+
+class Car(models.Model):
+    name = models.CharField(max_length=20)
+    owner = models.ForeignKey(Dude, related_name='cars_owned')
+
+    objects = PassThroughManager(DudeQuerySet)
+
+
+class SpotQuerySet(models.query.QuerySet):
+    def closed(self):
+        return self.filter(closed=True)
+
+    def secured(self):
+        return self.filter(secure=True)
+
+
+class Spot(models.Model):
+    name = models.CharField(max_length=20)
+    secure = models.BooleanField(default=True)
+    closed = models.BooleanField(default=False)
+    owner = models.ForeignKey(Dude, related_name='spots_owned')
+
+    objects = PassThroughManager.for_queryset_class(SpotQuerySet)()

File model_utils/tests/tests.py

     InheritanceManagerTestParent, InheritanceManagerTestChild1,
     InheritanceManagerTestChild2, TimeStamp, Post, Article, Status,
     StatusPlainTuple, TimeFrame, Monitored, StatusManagerAdded,
-    TimeFrameManagerAdded, Entry, Dude, SplitFieldAbstractParent)
+    TimeFrameManagerAdded, Entry, Dude, SplitFieldAbstractParent, Car, Spot)
 
 
 
         saltyqs = pickle.dumps(qs)
         unqs = pickle.loads(saltyqs)
         self.assertEqual(unqs.by_name('The Dude').count(), 1)
+
+    def test_queryset_not_available_on_related_manager(self):
+        dude = Dude.objects.by_name('Duder').get()
+        Car.objects.create(name='Ford', owner=dude)
+        self.assertFalse(hasattr(dude.cars_owned, 'by_name'))
+
+
+class CreatePassThroughManagerTests(TestCase):
+    def setUp(self):
+        self.dude = Dude.objects.create(name='El Duderino')
+        Spot.objects.create(name='The Crib', owner=self.dude, closed=True,
+                            secure=True)
+
+    def test_reverse_manager(self):
+        self.assertEqual(self.dude.spots_owned.closed().count(), 1)
+
+    def test_related_queryset_pickling(self):
+        qs = self.dude.spots_owned.closed()
+        pickled_qs = pickle.dumps(qs)
+        unpickled_qs = pickle.loads(pickled_qs)
+        self.assertEqual(unpickled_qs.secured().count(), 1)