クラスベースのビューでのミックスインの使用—Djangoドキュメント
クラスベースのビューでミックスインを使用する
Djangoの組み込みのクラスベースのビューは多くの機能を提供しますが、その一部は個別に使用することをお勧めします。 たとえば、HTTP応答を作成するためにテンプレートをレンダリングするビューを作成したいが、 TemplateView を使用することはできません。 おそらく、POST
でのみテンプレートをレンダリングする必要があり、GET
はまったく別のことを行います。 TemplateResponse を直接使用することもできますが、これによりコードが重複する可能性があります。
このため、Djangoは、より個別の機能を提供する多数のミックスインも提供しています。 たとえば、テンプレートレンダリングは、 TemplateResponseMixin にカプセル化されています。 Djangoリファレンスドキュメントには、すべてのミックスインの完全なドキュメントが含まれています。
コンテキストとテンプレートの応答
クラスベースのビューでテンプレートを操作するための一貫したインターフェイスを提供するのに役立つ2つの中央ミックスインが提供されています。
TemplateResponseMixin
TemplateResponse を返すすべての組み込みビューは、
TemplateResponseMixin
が提供する render_to_response()メソッドを呼び出します。 ほとんどの場合、これは自動的に呼び出されます(たとえば、 TemplateView と DetailView の両方によって実装されるget()
メソッドによって呼び出されます)。 同様に、オーバーライドする必要はほとんどありませんが、Djangoテンプレートを介してレンダリングされていないものを応答で返す場合は、オーバーライドする必要があります。 この例については、 JSONResponseMixinの例を参照してください。render_to_response()
自体が get_template_names()を呼び出します。これは、デフォルトでは、クラスベースのビューで template_name を検索するだけです。 他の2つのミックスイン( SingleObjectTemplateResponseMixin および MultipleObjectTemplateResponseMixin )はこれをオーバーライドして、実際のオブジェクトを処理するときに、より柔軟なデフォルトを提供します。ContextMixin
テンプレートのレンダリング(上記の
TemplateResponseMixin
を含む)など、コンテキストデータを必要とするすべての組み込みビューは、 get_context_data()を呼び出して、キーワード引数として確実にデータを渡す必要があります。 。get_context_data()
は辞書を返します。ContextMixin
では、キーワード引数を返すだけですが、これをオーバーライドして、辞書にメンバーを追加するのが一般的です。 extra_context 属性を使用することもできます。
Djangoの一般的なクラスベースのビューを構築する
Djangoの2つの汎用クラスベースビューが、個別の機能を提供するミックスインからどのように構築されているかを見てみましょう。 オブジェクトの「詳細」ビューをレンダリングする DetailView と、通常はクエリセットからオブジェクトのリストをレンダリングし、オプションでそれらをページングする ListView を検討します。 これにより、4つのミックスインが紹介されます。これらのミックスインは、単一のDjangoオブジェクトまたは複数のオブジェクトを操作するときに便利な機能を提供します。
汎用編集ビュー( FormView 、およびモデル固有のビュー CreateView 、 UpdateView 、 DeleteView )に関連するミックスインもあります。日付ベースの一般的なビュー。 これらは mixinリファレンスドキュメントでカバーされています。
DetailView:単一のDjangoオブジェクトを操作する
オブジェクトの詳細を表示するには、基本的に2つのことを行う必要があります。オブジェクトを検索してから、適切なテンプレートを使用して TemplateResponse を作成し、そのオブジェクトをコンテキストとして作成する必要があります。
オブジェクトを取得するために、 DetailView は SingleObjectMixin に依存します。このメソッドは、リクエストのURLに基づいてオブジェクトを特定する get_object()メソッドを提供します( URLConfで宣言されているpk
およびslug
キーワード引数の場合、ビューの model 属性または queryset のいずれかからオブジェクトを検索します。 ]属性(提供されている場合)。 SingleObjectMixin
は、 get_context_data()もオーバーライドします。これは、テンプレートレンダリングのコンテキストデータを提供するために、すべてのDjangoの組み込みクラスベースビューで使用されます。
次に、 TemplateResponse を作成するために、 DetailView は SingleObjectTemplateResponseMixin を使用します。その上。 実際にはかなり洗練されたオプションのセットを提供しますが、ほとんどの人が使用する主なオプションは<app_label>/<model_name>_detail.html
です。 _detail
の部分は、サブクラスの template_name_suffix を別のものに設定することで変更できます。 (たとえば、汎用編集ビューは、ビューの作成と更新に_form
を使用し、ビューの削除に_confirm_delete
を使用します。)
ListView:多くのDjangoオブジェクトを操作する
オブジェクトのリストはほぼ同じパターンに従います。オブジェクトの(ページ付けされている可能性がある)リスト(通常は QuerySet )が必要です。次に、それを使用して適切なテンプレートで TemplateResponse を作成する必要があります。オブジェクトのリスト。
オブジェクトを取得するために、 ListView は MultipleObjectMixin を使用します。これは、 get_queryset()と paginate_queryset()の両方を提供します。 SingleObjectMixin とは異なり、使用するクエリセットを特定するためにURLの一部をキーオフする必要がないため、デフォルトでは queryset または model が使用されます。ビュークラスの属性。 ここで get_queryset()をオーバーライドする一般的な理由は、現在のユーザーに応じてオブジェクトを動的に変更したり、ブログの将来の投稿を除外したりするためです。
MultipleObjectMixin は、 get_context_data()もオーバーライドして、ページ付けに適切なコンテキスト変数を含めます(ページ付けが無効になっている場合はダミーを提供します)。 object_list
がキーワード引数として渡され、 ListView がそれを調整することに依存しています。
TemplateResponse を作成するには、 ListView は MultipleObjectTemplateResponseMixin を使用します。 上記の SingleObjectTemplateResponseMixin と同様に、これはget_template_names()
をオーバーライドして、さまざまなオプションを提供します。最も一般的に使用されるのは、<app_label>/<model_name>_list.html
と[X288X ] の部分は、 template_name_suffix 属性から再び取得されます。 (日付ベースの汎用ビューは、_archive
、_archive_year
などのサフィックスを使用して、さまざまな特殊な日付ベースのリストビューに異なるテンプレートを使用します。)
Djangoのクラスベースのビューミックスインを使用する
これで、Djangoの汎用クラスベースビューが提供されたミックスインをどのように使用するかを見てきました。それらを組み合わせることができる他の方法を見てみましょう。 もちろん、これらを組み込みのクラスベースのビューまたは他の一般的なクラスベースのビューと組み合わせる予定ですが、Djangoが提供するよりも、解決できるまれな問題がいくつかあります。 。
警告
すべてのミックスインを一緒に使用できるわけではなく、すべての汎用クラスベースのビューを他のすべてのミックスインで使用できるわけではありません。 ここでは、機能するいくつかの例を示します。 他の機能をまとめたい場合は、使用している異なるクラス間で重複する属性とメソッド間の相互作用、およびメソッド解決順序がメソッドのどのバージョンにどのように影響するかを考慮する必要があります。どのような順序で呼び出されます。
Djangoのクラスベースのビューとクラスベースのビューミックスインのリファレンスドキュメントは、どの属性とメソッドが異なるクラスとミックスインの間で競合を引き起こす可能性があるかを理解するのに役立ちます。
疑わしい場合は、 View または TemplateView をベースにして、おそらく SingleObjectMixin および MultipleObjectMixin を使用する方がよい場合がよくあります。 おそらくより多くのコードを書くことになりますが、後で他の誰かがコードに来ることを明確に理解できる可能性が高く、心配するインタラクションが少なくなると、思考を節約できます。 (もちろん、問題に取り組む方法についてのインスピレーションを得るために、Djangoの一般的なクラスベースのビューの実装にいつでも浸ることができます。)
ビューでSingleObjectMixinを使用する
POST
にのみ応答する単純なクラスベースのビューを記述したい場合は、 View をサブクラス化し、そのサブクラスにpost()
メソッドを記述します。 ただし、URLから識別される特定のオブジェクトで処理を機能させる場合は、 SingleObjectMixin によって提供される機能が必要になります。
これは、汎用クラスベースビューの紹介で使用したAuthor
モデルで説明します。
views.py
実際には、リレーショナルデータベースではなく、Key-Valueストアに関心を記録したいと思うかもしれないので、そのビットは省略しました。 SingleObjectMixin の使用について心配する必要があるのは、self.get_object()
を呼び出すだけで、関心のある作成者を検索する場所だけです。 他のすべてはmixinによって私たちのために世話をされます。
これをURLに簡単にフックできます。
urls.py
pk
という名前のグループに注意してください。 get_object()はAuthor
インスタンスを検索するために使用します。 スラッグ、または SingleObjectMixin の他の機能のいずれかを使用することもできます。
SingleObjectMixinとListViewの使用
ListView は組み込みのページ付けを提供しますが、すべて(外部キーによって)別のオブジェクトにリンクされているオブジェクトのリストをページ付けしたい場合があります。 私たちの出版の例では、特定の出版社によるすべての本をめくりたいと思うかもしれません。
これを行う1つの方法は、 ListView を SingleObjectMixin と組み合わせて、ページ付けされた書籍のリストのクエリセットが単一のオブジェクトとして見つかった出版社にぶら下がることができるようにすることです。 これを行うには、2つの異なるクエリセットが必要です。
Book
ListView で使用するクエリセット- リストしたい本の
Publisher
にアクセスできるので、get_queryset()
をオーバーライドして、Publisher
の逆外部キーマネージャーを使用するだけです。 Publisher
get_object()で使用するクエリセット- 正しい
Publisher
オブジェクトをフェッチするには、get_object()
のデフォルトの実装に依存します。 ただし、queryset
引数を明示的に渡す必要があります。そうしないと、get_object()
のデフォルトの実装がget_queryset()
を呼び出し、オーバーライドしてBook
オブジェクトを返す代わりになります。Publisher
のもの。
ノート
get_context_data()
について慎重に考える必要があります。 SingleObjectMixin と ListView はどちらも、設定されている場合はcontext_object_name
の値でコンテキストデータに格納されるため、代わりにPublisher
を明示的に確認します。 ]はコンテキストデータにあります。 ListView は、super()
と呼ぶことを忘れない限り、適切なpage_obj
とpaginator
を追加します。
これで、新しいPublisherDetail
を作成できます。
self.object
をget()
内に設定して、後でget_context_data()
およびget_queryset()
で再び使用できるようにする方法に注目してください。 template_name
を設定しない場合、テンプレートはデフォルトで通常の ListView の選択になります。この場合、本のリストであるため"books/book_list.html"
になります。 ListView は SingleObjectMixin について何も知らないため、このビューがPublisher
と関係があるという手がかりはありません。
この例では、paginate_by
は意図的に小さいため、ページネーションが機能することを確認するために大量の本を作成する必要はありません。 使用したいテンプレートは次のとおりです。
より複雑なものは避けてください
通常、 TemplateResponseMixin および SingleObjectMixin は、それらの機能が必要な場合に使用できます。 上に示したように、少し注意すれば、SingleObjectMixin
を ListView と組み合わせることもできます。 ただし、そうしようとすると状況はますます複雑になります。大まかな目安は次のとおりです。
ヒント
各ビューは、一般的なクラスベースのビューのグループ( detail、list 、 editing 、およびdate)のいずれかからのミックスインまたはビューのみを使用する必要があります。 たとえば、 TemplateView (組み込みビュー)を MultipleObjectMixin (一般的なリスト)と組み合わせるのは問題ありませんが、SingleObjectMixin
(一般的な詳細)の組み合わせで問題が発生する可能性があります。 MultipleObjectMixin
(一般的なリスト)を使用します。
より洗練されたものにしようとするとどうなるかを示すために、より単純なソリューションがある場合に読みやすさと保守性を犠牲にする例を示します。 まず、 DetailView と FormMixin を組み合わせて、Django Form を同じURLにPOST
できるようにするという素朴な試みを見てみましょう。 ' DetailView を使用してオブジェクトを表示しています。
FormMixinとDetailViewの使用
View と SingleObjectMixin を一緒に使用した以前の例を思い出してください。 特定の著者に対するユーザーの関心を記録していました。 なぜ彼らが彼らを好きなのかというメッセージを彼らに残させたいと今言ってください。 繰り返しになりますが、これをリレーショナルデータベースに保存するのではなく、ここでは気にしない、より難解なものに保存するとします。
この時点で、 Form にアクセスして、ユーザーのブラウザーからDjangoに送信される情報をカプセル化するのは自然なことです。 また、 REST に多額の投資を行っているため、ユーザーからのメッセージをキャプチャする場合と同じURLを使用して作成者を表示するとします。 そのためにAuthorDetailView
を書き直してみましょう。
GET
の処理は DetailView から保持しますが、 Form をコンテキストデータに追加して、テンプレートでレンダリングできるようにする必要があります。 また、 FormMixin からフォーム処理を取り込み、POST
でフォームが適切に呼び出されるようにコードを記述します。
ノート
FormMixin を使用し、 DetailView を FormView (すでに適切なpost()
を提供している)と混合しようとするのではなく、post()
を自分で実装します)両方のビューがget()
を実装しているため、事態はさらに混乱します。
新しいAuthorDetail
は次のようになります。
get_success_url()
は、リダイレクト先の場所を提供しているだけです。これは、form_valid()
のデフォルトの実装で使用されます。 前述のように、独自のpost()
を提供する必要があります。
より良い解決策
FormMixin と DetailView の間の微妙な相互作用の数が、物事を管理する能力をすでにテストしていることは明らかです。 この種のクラスを自分で作成することはまずありません。
この場合、post()
メソッドを自分で作成するだけで、 DetailView を唯一の汎用機能として維持するのはかなり簡単ですが、 Form 処理コードの作成には多くの作業が必要です。重複の。
または、上記のアプローチよりも、フォームを処理するための個別のビューを用意する方が簡単です。このビューでは、 DetailView とは別の FormView を問題なく使用できます。
別のより良い解決策
ここで実際にやろうとしているのは、同じURLから2つの異なるクラスベースのビューを使用することです。 では、なぜそれだけをしないのですか? ここでは非常に明確な区分があります。GET
リクエストは DetailView ( Form がコンテキストデータに追加されている)とPOST
リクエストを取得する必要があります FormView を取得する必要があります。 まず、これらのビューを設定しましょう。
AuthorDisplay
ビューは、AuthorDetail を最初に導入したときのとほぼ同じです。 AuthorInterestForm
をテンプレートで使用できるようにするには、独自のget_context_data()
を作成する必要があります。 わかりやすくするために、以前のget_object()
オーバーライドはスキップします。
その場合、AuthorInterest
は単純な FormView ですが、 SingleObjectMixin を取り込む必要があります。これにより、話している作成者を見つけることができます。 template_name
を設定して、フォームエラーがAuthorDisplay
がGET
で使用しているのと同じテンプレートをレンダリングするようにします。
最後に、これを新しいAuthorDetail
ビューにまとめます。 クラスベースのビューで as_view()を呼び出すと、関数ベースのビューとまったく同じように動作するものが得られることはすでにわかっているので、2つのサブビューから選択した時点でそれを実行できます。
もちろん、AuthorInterest
の動作を別のURLにも表示したいが、別のテンプレート:
このアプローチは、他の一般的なクラスベースのビュー、または View または TemplateView から直接継承する独自のクラスベースのビューでも使用できます。これは、さまざまなビューを可能な限り分離するためです。 。
HTMLだけではありません
クラスベースのビューが優れているのは、同じことを何度もやりたいときです。 APIを作成していて、すべてのビューがレンダリングされたHTMLではなくJSONを返す必要があるとします。
すべてのビューで使用するミックスインクラスを作成して、JSONへの変換を1回処理できます。
たとえば、単純なJSONミックスインは次のようになります。
このミックスインは、 render_to_response()と同じシグネチャを持つrender_to_json_response()
メソッドを提供します。 これを使用するには、たとえばTemplateView
にミックスし、render_to_response()
をオーバーライドして、代わりにrender_to_json_response()
を呼び出す必要があります。
同様に、一般的なビューの1つでミックスインを使用することもできます。 JSONResponseMixin
をdjango.views.generic.detail.BaseDetailView
と混合することで DetailView の独自のバージョンを作成できます–(テンプレートのレンダリング動作が混合される前の DetailView ):
このビューは、他の DetailView と同じ方法で展開できますが、応答の形式を除いて、まったく同じ動作をします。
本当に冒険したい場合は、HTTPリクエストのプロパティに応じて、 HTMLとJSONの両方のコンテンツを返すことができる DetailView サブクラスを混在させることもできます。クエリ引数またはHTTPヘッダー。 JSONResponseMixin
と SingleObjectTemplateResponseMixin の両方をミックスし、 render_to_response()の実装をオーバーライドして、応答のタイプに応じて適切なレンダリングメソッドを延期するだけです。ユーザーがリクエストしました:
Pythonがメソッドのオーバーロードを解決する方法のため、super().render_to_response(context)
の呼び出しは、 TemplateResponseMixin の render_to_response()実装を呼び出すことになります。