28
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DjangoAdvent Calendar 2018

Day 21

DjangoのCustom ManagerとCustom QuerySetについて

Last updated at Posted at 2018-12-21

はじめに

この記事は、Django Advent Calendar 2018 21日目の記事です。

話すこと

全然たいしたことじゃないですけどtipsとして、最近気に入ってるカスタムManagerの書き方を紹介します。

Manager.from_queryset

「Managerで定義したメソッドをQuerySetとしても使いたい(逆のパターンも然り)」といったユースケースけっこうあると思います。そんなときに、Manager.from_querysetを使ってManagerを生成するとシンプルに実装できておすすめです。

公式ドキュメント: https://docs.djangoproject.com/en/2.1/topics/db/managers/#from-queryset

you might want both a custom Manager and a custom QuerySet. You can do that by calling Manager.from_queryset() which returns a subclass of your base Manager with a copy of the custom QuerySet methods:

Manager.from_querysetを呼び出すことで、カスタムQuerySetのメソッドを備えているManagerのサブクラスを取得できるよって書いてます。

実際にコードに落とし込んで見てみましょう。

class Todo(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, default='')
    assignee = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.SET_NULL)
    start = models.DateField(null=True, blank=True)
    end = models.DateField(null=True, blank=True)
    is_active = models.BooleanField(default=True)

このようなTodoモデルを用意します。ここでアクティブなTodoだけ(is_active=True)を取得したいという要望がでてきたとしましょう。さっそくManager.from_querysetを使って追加実装してみます。

class TodoQuerySet(models.QuerySet):
    def filter_active(self):
        return self.filter(is_active=True)


class TodoQueryManager(
        models.Manager.from_queryset(TodoQuerySet)):
    pass


class Todo(models.Model):
    objects = TodoQueryManager()

    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, default='')
    assignee = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='todos', blank=True, null=True, on_delete=models.SET_NULL)
    start = models.DateField(null=True, blank=True)
    end = models.DateField(null=True, blank=True)
    is_active = models.BooleanField(default=True)

これで以下のようにManager, QuerySet両方で、アクティブなTodoを取得するfilter_active()メソッドを使うことができるようになります。

  • Todo.objects.filter_active()
  • user.todos.filter_active()

同じ実装を2回しないで済むので、シンプルでいいですね。

終わりに

このやり方は、TakesxiSximadaに教えてもらいました 。ありがとうございます :pray:
それでは メリークリスマス :christmas_tree:

28
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?