# Django 5.0.9.dev20240806133106 ドキュメント

# マネージャ

class `Manager`

`マネージャ (Manager)` とは、Django のモデルに対するデータベースクエリの操作を提供するインターフェイスです。Django アプリケーション内の1つのモデルに対して、`Manager` は最低でも1つは存在します。

`Manager` クラスの詳細については、クエリを作成する に書かれています。ここでは、特に、`Manager` の動作をカスタマイズするモデルのオプションについて説明しています。

## マネージャの名前

デフォルトでは、Django は `objects` という名前の `Manager` を各 Django モデルクラスに対して追加します。しかし、もし `objects` をフィールド名として使いたい場合や、あるいは、`Manager` に対して `objects` 以外の名前を使いたい場合には、各モデル単位で好きな名前を付けることができます。あるクラスの `Manager` の名前を変えるには、そのクラスの上で `models.Manager()` と書いて、クラス変数を定義します。たとえば、次のように書きます。

    from django.db import models

    class Person(models.Model):
        # ...
        people = models.Manager()

このモデル例を使うと、`Person.objects` は `AttributeError` 例外を起こしますが、`Person.people.all()` と書けば、すべての `Person` オブジェクトのリストが得られます。

## マネージャのカスタマイズ

`Manager` ベースクラスを拡張し、カスタマイズした `Manager` をモデル内でインスタンス化すれば、特定のモデル用にカスタマイズした `Manager` を使うことができます。

`Manager` をカスタマイズしたくなるシチュエーションとしては、たとえば次の2つのような場合が考えられます。1つ目は、`Manager` に新しいメソッドを追加したい場合、もう1つは、`Manager` が最初に返す `QuerySet` を修正したい場合です。

### マネージャに新しいメソッドを追加する

`Manager` に新しいメソッドを追加するのがふさわしいのは、モデルに対する「テーブルレベル」での操作を追加したい場合です。(「低レベル」の機能、たとえば、あるモデルオブジェクトの1つのインスタンスに作用するような関数の場合には、`Manager` をカスタマイズするのではなく、モデルメソッド を使ってください。

たとえば、このカスタム `Manager` は `with_counts()` メソッドを追加します:

    from django.db import models
    from django.db.models.functions import Coalesce

    class PollManager(models.Manager):
        def with_counts(self):
            return self.annotate(num_responses=Coalesce(models.Count("response"), 0))

    class OpinionPoll(models.Model):
        question = models.CharField(max_length=200)
        objects = PollManager()

    class Response(models.Model):
        poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
        # ...

この例では、 `OpinionPoll.objects.with_counts()` を使うことで、 `num_responses` 属性が付加された `OpinionPoll` オブジェクトの `QuerySet` を得ることができます。

`Manager` のカスタマイズメソッドは、どんなオブジェクトを返しても構いませんが、`QuerySet` だけは返してはいけません。

注目すべきもう1つの点は、 `Manager` 内のメソッドではself.modelとすることで、 `Manager` に紐づいているモデルクラスを取得できることです。

### マネージャが初めに返す `QuerySet` を修正する

`Manager` のベース `QuerySet` は、すべてのオブジェクトを返します。 たとえば、このモデルの例では...:

    from django.db import models

    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)

`Book.objects.all()` は、データベース内の全ての本を返します。

`Manager.get_queryset()` メソッドをオーバーライドすることで、 `Manager` のベース `QuerySet` を上書きできます。 `get_queryset()` は、必要な属性を含む `QuerySet` を返す必要があります。

例えば、次のモデルには 2つ の `Manager` があります。片方はすべてのオブジェクトを返し、もう片方はRoald Dahlの本のみを返します:

    # First, define the Manager subclass.
    class DahlBookManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(author="Roald Dahl")

    # Then hook it into the Book model explicitly.
    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)

        objects = models.Manager()  # The default manager.
        dahl_objects = DahlBookManager()  # The Dahl-specific manager.

このモデルの例では、 `Book.objects.all()` はデータベース上の本を全て返 しますが、 `Book.dahl_objects.all()` は Roald Dahl の書いた本だけを返しま す。

`get_queryset()` は `QuerySet` オブジェクトを返すので、 `filter()` 、 `exclude()` 、その他の `QuerySet` オブジェクトのメソッドを全て使えます。したがって、以下のような文も実行できます。

    Book.dahl_objects.all()
    Book.dahl_objects.filter(title="Matilda")
    Book.dahl_objects.count()

この例では、同じモデルで複数のマネージャを使用するという、追加の面白いテクニックも紹介しました。一つのモデルに対して、好きなだけ `Manager()` インスタンスを割り当てることができます。これは、何度も同じコードを書かずにモデルに共通の "フィルタ" を定義するための方法です。

例:

    class AuthorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role="A")

    class EditorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role="E")

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
        people = models.Manager()
        authors = AuthorManager()
        editors = EditorManager()

この例では、`Person.authors.all()`、`Person.editors.all()`、`Person.people.all()` を指定でき、期待通りの結果が得られます。

### デフォルトマネージャ

`Model.``_default_manager`

カスタムの `Manager` オブジェクトを使う場合、 Django が (モデル内で定義された順番で) 最初に見つけた `Manager` には特別なステータスがあることに注意してください。Django はクラスで定義された最初の `Manager` を「デフォルト」の `Manager` と解釈し、Django の一部の機能 (`dumpdata` を含む) はそのモデル専用にその `Manager` を使用します。その結果、`get_queryset()` をオーバーライドした結果、利用したいオブジェクトを取得できなくなるという事態を避けるために、デフォルトマネージャの選択には注意した方が良いでしょう。

カスタムのデフォルトマネージャは `Meta.default_manager_name` で指定できます。

たとえば、ジェネリックビューを実装しているサードパーティのアプリで、未知のモデルを扱わなければならないコードを書いている場合、モデルが `objects` マネージャを持っていると仮定するのではなく、このマネージャ (または `_base_manager`) を使用してください。

### ベースマネージャ

`Model.``_base_manager`

#### マネージャによるリレーション先オブジェクトへのアクセス

デフォルトでは、Django はリレーション先オブジェクト (例えば `choice.question`) にアクセスする際に、リレーション先オブジェクトの `_default_manager` ではなく、 `Model._base_manager` マネージャクラスのインスタンスを使います。これは Django がリレーション先オブジェクトを取得できるようにする必要があるためで、そうしないとデフォルトマネージャでフィルタリングされてしまう (つまりアクセスできない) からです。

通常のベースマネージャクラス (`django.db.models.Manager`) があなたの環境に合わない場合、 `Meta.base_manager_name` を設定することで、 Django にどのクラスを使うかを指示できます。

ベースマネージャはリレーション先モデルのクエリや、1対多や多対多のリレーションシップ にアクセスする場合には使用されません。たとえば、 チュートリアルの `Question` モデルに `deleted` フィールドがあり、 `deleted=True` のインスタンスをフィルタリングするベースマネージャがあった場合、`Choice.objects.filter(question__name__startswith='What')` のようなクエリセットには削除された質問に関連する選択肢が含まれます。

#### このタイプのマネージャのサブクラスでは、結果をフィルタリングしないでください。

このマネージャは、他のモデルからリレーション先オブジェクトにアクセスするために 使用されます。このような状況では、 Django は、参照されるオブジェクトを すべて 取得できるように、取得するモデルのすべてのオブジェクトを見ることができなければなりません。

したがって、 `get_queryset()` をオーバーライドして行をフィルタリングしてはいけません。もしそうすれば、 Django は不完全な結果を返します。

### カスタマイズした `QuerySet` のメソッド をマネージャから呼び出す

標準の `QuerySet` のほとんどのメソッドは `Manager` から直接アクセスできますが、カスタムの `QuerySet` で定義したメソッドは `Manager` でも実装する必要があります:

    class PersonQuerySet(models.QuerySet):
        def authors(self):
            return self.filter(role="A")

        def editors(self):
            return self.filter(role="E")

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

        def authors(self):
            return self.get_queryset().authors()

        def editors(self):
            return self.get_queryset().editors()

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
        people = PersonManager()

この例では `authors()` と `editors()` の両方をマネージャ `Person.people` から直接呼び出すことができます。

### `QuerySet` のメソッドで、マネージャを生成する

`QuerySet` と `Manager` の両方でメソッドを複製する必要がある上記の方法の代わりに、 `QuerySet.as_manager()` を使用すると、カスタムした `QuerySet` のメソッドをコピーした `Manager` のインスタンスを作成できます:

    class Person(models.Model):
        ...
        people = PersonQuerySet.as_manager()

`QuerySet.as_manager()` によって生成される `Manager` インスタンスは、前の例の `PersonManager` とほぼ同じになります。

すべての `QuerySet` メソッドが `Manager` レベルで意味を持つわけではありません。例えば、 `QuerySet.delete()` メソッドが `Manager` クラスにコピーされることは意図的に防いであります。

メソッドは以下の規則に従ってコピーされます:

- パブリックメソッドはデフォルトでコピーされます。
- プライベートメソッド (アンダースコアで始まるメソッド) は、デフォルトではコピーされません。
- `queryset_only` 属性が `False` に設定されているメソッドは常にコピーされます。
- `queryset_only` 属性が `True` に設定されているメソッドはコピーされません。

例:

    class CustomQuerySet(models.QuerySet):
        # Available on both Manager and QuerySet.
        def public_method(self):
            return

        # Available only on QuerySet.
        def _private_method(self):
            return

        # Available only on QuerySet.
        def opted_out_public_method(self):
            return

        opted_out_public_method.queryset_only = True

        # Available on both Manager and QuerySet.
        def _opted_in_private_method(self):
            return

        _opted_in_private_method.queryset_only = False

#### `from_queryset()`

classmethod `from_queryset`(queryset_class)

高度な使い方をする場合には、カスタムの `Manager` とカスタムの `QuerySet` の両方が必要になるかもしれません。この場合、 `Manager.from_queryset()` を呼び出すことで、カスタム `QuerySet` メソッドをコピーしたベース `Manager` の サブクラス を返すことができます:

    class CustomManager(models.Manager):
        def manager_only_method(self):
            return

    class CustomQuerySet(models.QuerySet):
        def manager_and_queryset_method(self):
            return

    class MyModel(models.Model):
        objects = CustomManager.from_queryset(CustomQuerySet)()

生成されたクラスを変数に格納することもできます:

    MyManager = CustomManager.from_queryset(CustomQuerySet)

    class MyModel(models.Model):
        objects = MyManager()

### カスタムマネージャとモデルの継承

Django がカスタムマネージャと モデルの継承 をどのように扱うかを以下に示します:

1. Python の通常の名前解決順序を使って (子クラスの名前は他を全て上書きし、次に最初の親クラスの名前、 というように) 、基底クラスのマネージャは常に子クラスに継承されます。
2. モデルやその親クラスでマネージャが宣言されていない場合、Django は自動的に `objects` マネージャを作成します。
3. クラスのデフォルトマネージャは `Meta.default_manager_name` で選択されたマネージャか、モデル上で最初に宣言されたマネージャか、最初の親モデルのデフォルトマネージャです。

これらのルールは、抽象的な基底クラスを経由して、カスタムマネージャのコレクションをモデルのグループにインストールしたい場合でも、デフォルトのマネージャをカスタマイズするために必要な柔軟性を提供します。たとえば、次のような基底クラスがあるとします:

    class AbstractBase(models.Model):
        # ...
        objects = CustomManager()

        class Meta:
            abstract = True

これを子クラスで直接使用した場合、子クラスでマネージャを宣言していなければ `objects` がデフォルトのマネージャになります:

    class ChildA(AbstractBase):
        # ...
        # This class has CustomManager as the default manager.
        pass

もし `AbstractBase` を継承して別のデフォルトマネージャを指定したい場合は、子クラスにそのデフォルトマネージャを指定できます:

    class ChildB(AbstractBase):
        # ...
        # An explicit default manager.
        default_manager = OtherManager()

上記では `default_manager` がデフォルトです。 `objects` マネージャは継承されているのでまだ使用可能ですが、デフォルトでは使用されません。

最後に、この例では `AbstractBase` のデフォルトを使用しつつ、子クラスに追加のマネージャを追加したいとします。 新しいマネージャを子クラスに直接追加することはできません。デフォルトをオーバーライドすることになり、抽象基底クラスのすべてのマネージャを明示的にインクルードする必要があるからです。解決策としては、追加のマネージャを別の基底クラスに置き、それをデフォルトクラスの 後の 継承階層に含めることです:

    class ExtraManager(models.Model):
        extra_manager = OtherManager()

        class Meta:
            abstract = True

    class ChildC(AbstractBase, ExtraManager):
        # ...
        # Default manager is CustomManager, but OtherManager is
        # also available via the "extra_manager" attribute.
        pass

抽象モデル上でカスタムマネージャを 定義 することはできますが、抽象モデルを使ってメソッドを 呼び出す ことはできないことに注意してください。 つまり:

    ClassA.objects.do_something()

上記は有効なコードですが、:

    AbstractBase.objects.do_something()

上記では例外が発生します。 これはマネージャがオブジェクトのコレクションを管理するためのロジックをカプセル化することを想定しているためです。抽象オブジェクトのコレクションを持つことはできないので、それらを管理することは意味がありません。抽象モデルに適用される機能がある場合、その機能は抽象モデルの staticmethod か classmethod に置くべきです。

### 実装する際の注意

カスタムマネージャにどのような機能を追加するにしても、マネージャインスタンスの浅いコピーを作成できることが必須です:

    >>> import copy
    >>> manager = MyManager()
    >>> my_copy = copy.copy(manager)

Django は特定のクエリ中にマネージャオブジェクトの浅いコピーを作成します。マネージャがコピーできない場合、これらのクエリは失敗します。

ほとんどのカスタムマネージャでは問題にならないでしょう。単純なメソッドを `Manager` に追加するだけであれば、 `Manager` のインスタンスをコピー不可能にすることはまずありません。しかし、オブジェクトの状態をコントロールする `Manager` オブジェクトの `__getattr__` やその他のプライベートメソッドをオーバーライドする場合は、 `Manager` のコピー機能に影響を与えないようにする必要があります。