django-model-utilsをいろいろ試してみる その5 PassThroughManager

PassThroughManagerというものを試してみます。

まず普通のcustom managerを持つmodelを作成します。

from django.db import models
import pytz
from datetime import datetime

class PostManager(models.Manager):
    def by_author(self, user):
        return self.filter(user=user)

    def published(self, **kwargs):
        return self.filter(published__lte=datetime.utcnow().replace(tzinfo=pytz.utc), **kwargs)


class Post(models.Model):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=100)
    published = models.DateTimeField()
    objects = PostManager()
    # objects = PassThroughManager.for_queryset_class(PostQuerySet)()

    def __unicode__(self):
        return self.title


適当にレコードを作成します。

>>> from apps.models import Post
>>> from datetime import datetime, timedelta
>>> import pytz
>>> yesterday = datetime.utcnow().replace(tzinfo=pytz.utc) - timedelta(days=1)
>>> tomorrow = datetime.utcnow().replace(tzinfo=pytz.utc) + timedelta(days=1) 
>>> u = User.objects.all()[0]
>>> Post.objects.create(user=u, title='yesterday', published=yesterday)
<Post: yesterday>
>>> Post.objects.create(user=u, title='tomorrow', published=tomorrow)
<Post: tomorrow>


custom managerにby_authorとis_publishedを定義してますが、これらはチェインできません。

>>> Post.objects.published()
[<Post: yesterday>]
>>> Post.objects.by_author(u)
[<Post: yesterday>, <Post: tomorrow>]
>>> Post.objects.by_author(u).published()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'QuerySet' object has no attribute 'published'


そこでPassThroughManagerを使ってみます

from django.db import models
from django.db.models.query import QuerySet
import pytz
from datetime import datetime
from model_utils.managers import PassThroughManager


class PostQuerySet(QuerySet):
    def by_author(self, user):
        return self.filter(user=user)

    def published(self, **kwargs):
        return self.filter(published__lte=datetime.utcnow().replace(tzinfo=pytz.utc), **kwargs)


class Post(models.Model):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=100)
    published = models.DateTimeField()
    # objects = PostManager()
    objects = PassThroughManager.for_queryset_class(PostQuerySet)()

    def __unicode__(self):
        return self.title


なんと、チェインできるようになります。

>>> Post.objects.published()
[<Post: yesterday>]
>>> u = User.objects.all()[0]
>>> Post.objects.by_author(u)
[<Post: yesterday>, <Post: tomorrow>]
>>> Post.objects.by_author(u).published()
[<Post: yesterday>]


これは使えそうな気がします。


関連 : django-model-utilsをいろいろ試してみる その1 StatusModel - brainstorm
関連 : django-model-utilsをいろいろ試してみる その2 TimeFramedModel - brainstorm
関連 : django-model-utilsをいろいろ試してみる その3 InheritanceManager - brainstorm
関連 : django-model-utilsをいろいろ試してみる その4 ModelTracker - brainstorm
参考 : carljm / django-model-utils / source / ― Bitbucket