Edited at

Djangoでクエリに名前付けする

More than 3 years have passed since last update.


課題

Railsにはscopeという機能があって、頻出のクエリに名前付けを行うことができます。

class Post < ActiveRecord::Base

scope :published, -> { where(published: true) }
end

Post.published
# SELECT "posts".* FROM "posts" WHERE "posts"."published" = 1

同じようなことをDjangoでもやりたいな、と思ってやり方を調べました。


解決方法

カスタマイズしたQuerySetと、ModelManagerを使うと、実現できるようです。

https://docs.djangoproject.com/en/1.7/topics/db/managers/#calling-custom-queryset-methods-from-the-manager

from django.db import models

class PostQuerySet(models.QuerySet):
def published(self):
return self.filter(published=True)

def latest(self):
return self.order_by('-updated_at')

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

class Post(models.Model):
published = models.BooleanField()
# 他いろんなフィールド...

objects = PostManager() # custom managerを定義

使い方。

>>> Post.objects.all().published()

# SELECT "posts".* FROM "posts" WHERE "posts"."published" = 1

以下のようにチェーンさせることもできました。

>>> Post.objects.all().published().latest()

objects.all() などをつかってQuerySetを生成しないと使えないのがちょっと微妙な気もしますが、Viewなどが読みやすく実装できるようになると思います。