マネージャー
- class Manager
Manager
は、データベースクエリ操作をDjangoモデルに提供するためのインターフェイスです。 Djangoアプリケーションのすべてのモデルに少なくとも1つのManager
が存在します。
Manager
クラスの動作方法は、クエリの作成に記載されています。 このドキュメントでは、Manager
の動作をカスタマイズするモデルオプションについて具体的に触れています。
マネージャー名
デフォルトでは、DjangoはすべてのDjangoモデルクラスにobjects
という名前のManager
を追加します。 ただし、フィールド名としてobjects
を使用する場合、またはManager
にobjects
以外の名前を使用する場合は、名前を変更できます。 -モデルベース。 特定のクラスのManager
の名前を変更するには、そのモデルでタイプmodels.Manager()
のクラス属性を定義します。 例えば:
このサンプルモデルを使用すると、Person.objects
はAttributeError
例外を生成しますが、Person.people.all()
はすべてのPerson
オブジェクトのリストを提供します。
カスタムマネージャー
基本Manager
クラスを拡張し、モデルでカスタムManager
をインスタンス化することにより、特定のモデルでカスタムManager
を使用できます。
Manager
をカスタマイズする理由は2つあります。それは、Manager
メソッドを追加するため、および/または最初のQuerySet
を変更するためです。Manager
が返します。
マネージャーメソッドの追加
モデルに「テーブルレベル」の機能を追加するには、Manager
メソッドを追加することをお勧めします。 (「行レベル」の機能、つまりモデルオブジェクトの単一インスタンスに作用する関数の場合は、カスタムManager
メソッドではなく、モデルメソッドを使用します。)
カスタムManager
メソッドは、必要なものをすべて返すことができます。 QuerySet
を返す必要はありません。
たとえば、このカスタムManager
は、メソッドwith_counts()
を提供します。このメソッドは、すべてのOpinionPoll
オブジェクトのリストを返し、それぞれに追加のnum_responses
属性があります。集計クエリの:
この例では、OpinionPoll.objects.with_counts()
を使用して、num_responses
属性を持つOpinionPoll
オブジェクトのリストを返します。
この例についてもう1つ注意すべき点は、Manager
メソッドがself.model
にアクセスして、それらがアタッチされているモデルクラスを取得できることです。
マネージャーのイニシャルを変更するQuerySet
Manager
のベースQuerySet
は、システム内のすべてのオブジェクトを返します。 たとえば、次のモデルを使用します。
…ステートメントBook.objects.all()
は、データベース内のすべての本を返します。
Manager.get_queryset()
メソッドをオーバーライドすることで、Manager
のベースQuerySet
をオーバーライドできます。 get_queryset()
は、必要なプロパティを持つQuerySet
を返す必要があります。
たとえば、次のモデルには two Manager
があります。1つはすべてのオブジェクトを返し、もう1つはRoaldDahlの本だけを返します。
このサンプルモデルでは、Book.objects.all()
はデータベース内のすべての本を返しますが、Book.dahl_objects.all()
はRoaldDahlによって書かれた本のみを返します。
もちろん、get_queryset()
はQuerySet
オブジェクトを返すため、filter()
、exclude()
、およびその他すべてのQuerySet
メソッドを使用できます。 したがって、これらのステートメントはすべて合法です。
この例では、同じモデルで複数のマネージャーを使用するという別の興味深い手法も指摘されています。 モデルには、Manager()
インスタンスをいくつでもアタッチできます。 これは、モデルに共通の「フィルター」を定義する簡単な方法です。
例えば:
この例では、Person.authors.all()
、Person.editors.all()
、およびPerson.people.all()
を要求して、予測可能な結果を得ることができます。
デフォルトのマネージャー
- Model._default_manager
カスタムManager
オブジェクトを使用する場合、最初に遭遇するManager
Djangoが(モデルで定義されている順序で)特別なステータスを持つことに注意してください。 Djangoは、クラスで定義された最初のManager
を「デフォルト」Manager
として解釈し、Djangoのいくつかの部分(:djadmin: `dumpdata` を含む)はそれを使用します[そのモデル専用のX168X] 。 そのため、get_queryset()
をオーバーライドすると、操作するオブジェクトを取得できなくなる状況を回避するために、デフォルトマネージャーの選択に注意することをお勧めします。
Meta.default_manager_name を使用して、カスタムのデフォルトマネージャーを指定できます。
たとえば、ジェネリックビューを実装するサードパーティのアプリで、不明なモデルを処理する必要のあるコードを記述している場合は、モデルに[ X212X] マネージャー。
ベースマネージャー
- Model._base_manager
このタイプのマネージャーサブクラスの結果をフィルターで除外しないでください
このマネージャーは、他のモデルから関連するオブジェクトにアクセスするために使用されます。 このような状況では、Djangoは、フェッチしているモデルのすべてのオブジェクトを表示できる必要があります。これにより、参照されているすべてを取得できます。
get_queryset()
メソッドをオーバーライドして行をフィルターで除外すると、Djangoは誤った結果を返します。 そうしないでください。 結果をget_queryset()
でフィルタリングするマネージャーは、ベースマネージャーとしての使用には適していません。
マネージャーからカスタムQuerySetメソッドを呼び出す
標準のQuerySet
のほとんどのメソッドは、Manager
から直接アクセスできますが、これは、カスタムQuerySet
で定義された追加のメソッドの場合にのみ当てはまり、 Manager
:
この例では、マネージャーPerson.people
からauthors()
とeditors()
の両方を直接呼び出すことができます。
QuerySetメソッドを使用したマネージャーの作成
QuerySet
とManager
の両方でメソッドを複製する必要がある上記のアプローチの代わりに、 QuerySet.as_manager()を使用してManager
カスタムQuerySet
のメソッドのコピー:
QuerySet.as_manager()によって作成されたManager
インスタンスは、前の例のPersonManager
と実質的に同じになります。
すべてのQuerySet
メソッドがManager
レベルで意味をなすわけではありません。 たとえば、 QuerySet.delete()メソッドがManager
クラスにコピーされないように意図的に禁止しています。
メソッドは、次のルールに従ってコピーされます。
- パブリックメソッドはデフォルトでコピーされます。
- プライベートメソッド(アンダースコアで始まる)は、デフォルトではコピーされません。
queryset_only
属性がFalse
に設定されているメソッドは常にコピーされます。queryset_only
属性がTrue
に設定されているメソッドはコピーされません。
例えば:
from_queryset()
- classmethod from_queryset(queryset_class)
高度な使用法では、カスタムManager
とカスタムQuerySet
の両方が必要になる場合があります。 これを行うには、カスタムQuerySet
メソッドのコピーを使用してベースManager
のサブクラスを返すManager.from_queryset()
を呼び出します。
生成されたクラスを変数に格納することもできます。
カスタムマネージャーとモデルの継承
Djangoがカスタムマネージャーとモデル継承を処理する方法は次のとおりです。
- 基本クラスのマネージャーは、Pythonの通常の名前解決順序を使用して、常に子クラスに継承されます(子クラスの名前は他のすべての名前をオーバーライドし、最初の親クラスの名前になります)。
- モデルやその親でマネージャーが宣言されていない場合、Djangoは自動的に
objects
マネージャーを作成します。 - クラスのデフォルトマネージャーは、 Meta.default_manager_name で選択されたマネージャー、モデルで宣言された最初のマネージャー、または最初の親モデルのデフォルトマネージャーのいずれかです。
これらのルールは、抽象基本クラスを介してモデルのグループにカスタムマネージャーのコレクションをインストールする場合に必要な柔軟性を提供しますが、それでもデフォルトマネージャーをカスタマイズします。 たとえば、次の基本クラスがあるとします。
これをサブクラスで直接使用する場合、基本クラスでマネージャーを宣言しないと、objects
がデフォルトのマネージャーになります。
AbstractBase
から継承したいが、別のデフォルトマネージャーを提供する場合は、子クラスにデフォルトマネージャーを提供できます。
ここでは、default_manager
がデフォルトです。 objects
マネージャーは継承されているため、引き続き使用できます。 デフォルトとして使用されていないだけです。
最後に、この例では、子クラスにマネージャーを追加したいが、AbstractBase
のデフォルトを使用するとします。 新しいマネージャーを子クラスに直接追加することはできません。これは、デフォルトをオーバーライドし、抽象基本クラスのすべてのマネージャーも明示的に含める必要があるためです。 解決策は、追加のマネージャーを別の基本クラスに配置し、それをデフォルトの後の継承階層に導入することです。
抽象モデルでカスタムマネージャーを定義することはできますが、抽象モデルを使用してメソッドを呼び出すことはできないことに注意してください。 あれは:
は合法ですが:
例外が発生します。 これは、マネージャーがオブジェクトのコレクションを管理するためのロジックをカプセル化することを目的としているためです。 抽象オブジェクトのコレクションを持つことはできないため、それらを管理することは意味がありません。 抽象モデルに適用される機能がある場合は、その機能を抽象モデルのstaticmethod
またはclassmethod
に配置する必要があります。
実装上の懸念
カスタムManager
に追加する機能が何であれ、Manager
インスタンスの浅いコピーを作成できる必要があります。 つまり、次のコードが機能する必要があります。
Djangoは、特定のクエリ中にマネージャーオブジェクトの浅いコピーを作成します。 Managerをコピーできない場合、これらのクエリは失敗します。
これは、ほとんどのカスタムマネージャーにとって問題にはなりません。 Manager
に単純なメソッドを追加するだけの場合、Manager
のインスタンスを誤ってコピー不能にする可能性はほとんどありません。 ただし、__getattr__
またはオブジェクトの状態を制御するManager
オブジェクトのその他のプライベートメソッドをオーバーライドする場合は、Manager
の機能に影響を与えないようにする必要があります。 ]コピーされます。