Login

Custom Model Manager Chaining

Author:
hunterford
Posted:
July 19, 2010
Language:
Python
Version:
1.1
Score:
4 (after 4 ratings)

Using Python mixins, you can chain methods on your queryset.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from datetime import datetime

from django.db import models
from django.db.models.query import QuerySet

class PostMixin(object):
    def by_author(self, user):
        return self.filter(user=user)

    def published(self):
        return self.filter(published__lte=datetime.now())

class PostQuerySet(QuerySet, PostMixin):
    pass

class PostManager(models.Manager, PostMixin):
    def get_query_set(self):
        return PostQuerySet(self.model, using=self._db)

class Post(models.Model):
    user = models.ForeignKey(User)
    published = models.DateTimeField()

    objects = PostManager()

Post.objects.by_author(user=request.user).published()

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

jsdalton (on July 19, 2010):

I have started using this pattern myself (I suggested the author upload it here) and can confirm its awesomeness.

I've seen many attempts at queryset chaining in Django, and they are invariably complex and frequently quite brittle. This approach is astoundingly simple and easy to use.

My only complaint is that there's a tad bit more excess boilerplate code to get it working than would be ideal. The purpose of the boilerplate is probably opaque to someone stumbling upon it and not knowing what it's for.

#

gsakkis (on July 20, 2010):

""" My only complaint is that there's a tad bit more excess boilerplate code to get it working than would be ideal. """

Check out #2117 for a no-boilerplate extension of the same idea.

#

Please login first before commenting.