内藤 裕二/ 2022年 12月 23日/ 技術

こんにちは!内藤です!
だいぶ時間が経ってしまいましたが、前回の記事の続きです!

Index

  • 基本的なクラスのシーケンス(前回の記事
    • View
    • RedirectView
    • TemplateView
    • DetailView
    • ListView
  • CRUDクラスのシーケンス(この記事)
    • FormView
    • CreateView
    • UpdateView
    • DeleteView

前提条件

  • 対象のDjangoバージョンは、手元にあった 3.2.13 です
  • 現場で使える Django の教科書《基礎編》の内容程度が頭に入っている人向け
  • 対象とするクラスは、下記
    • View
    • RedirectView
    • TemplateView
    • DetailView
    • ListView
    • FormView
    • CreateView
    • UpdateView
    • DeleteView

django.views.generic.edit.FormView

入力を検証するためのFormを使用するViewです。
ソースコードはこちら
GETメソッド、POSTメソッドでFormの検証が通った場合、POSTメソッドでFormの検証が通らなかった場合にわけてコールグラフを起こしてみました。

GET時のコールグラフ

FormViewのコールグラフ(GET)

関数名 処理内容
FormMixIn.get_context_data テンプレートエンジンに渡すための context を生成します。
context には、FormView.get_form で生成した Form オブジェクトが 'form' というキー名で context に追加されます
FormMixIn.get_form 検証用の Form オブジェクトを生成します。
FormView.get_form_class メソッドで生成する Form クラスを取得し、 FormView.get_form_kwargs メソッドで Form クラスのインスタンスを生成します
FormMixIn.get_form_class 検証も使用する Form オブジェクトのクラス名を取得します。
デフォルトでは、クラスフィールド form_class を使用します
FormView.get_form_kwargs 検証に使用する Form オブジェクトのコンストラクタに渡す引数を dict として取得します。
下記のキーで、それぞれの値を設定します。
・キー'initial' ... Form オブジェクトに渡す初期値
キー'prefix' ... Form オブジェクトに渡すプレフィックス
・キー'data' ... POSTまたはPUTメソッドの時、渡されたデータ
・キー'files' ... POSTまたはPUTメソッドの時、アップロードされたファイルデータ
FormView.get_initial 検証に使用する Form オブジェクトの初期値を返します。
デフォルトでは、クラスフィールド initial を使用します
FormView.get_prefix 検証に使用する Form オブジェクトのプレフィックスを返します。
デフォルトでは、クラスフィールド prefix を使用します
ContextMixin.get_context_data django.views.generic.base.TemplateViewに記述した内容です。
TemplateResponseMixin.get_template_names レンダリングするテンプレート名をリストで返します。
クラス変数 template_name の内容を返します。
TemplateResponseMixin.render_to_response テンプレートをレンダリングしてレスポンスを返します。

入力検証に使用する Form オブジェクトを生成して、指定したテンプレートをレンダリングして返します。

POST, 検証OK時のコールグラフ

POSTメソッドで、検証に使用した Form オブジェクトの is_valid メソッドが True を返す場合です。

FormViewのコールグラフ(POST, 検証OK)

FormMixIn.get_form ~ FormView.get_prefix までの流れは GET メソッドの時と同じです。

関数名 処理内容
FormView.form_valid 検証用の Form オブジェクトによる検証がOKだった時に呼ばれます。
デフォルトでは、成功時のURLにリダイレクトします。
FormView.get_success_url 検証OKだった時のリダイレクト先を返します。
デフォルトでは、クラスフィールド success_url を返します。

POST, 検証NG時のコールグラフ

POSTメソッドで、検証に使用した Form オブジェクトの is_valid メソッドが False を返す場合です。

FormViewのコールグラフ(POST, 検証NG)

FormMixIn.get_form ~ FormView.get_prefix までの流れは GET メソッドの時と同じです。
また、FormMixIn.get_context_data 移行の流れも、GET メソッドの時と同じです。

関数名 処理内容
FormView.form_invalid 検証用の Form オブジェクトによる検証がNGだった時に呼ばれます。
get_context_data メソッドを呼び出して context を生成し、 render_to_response メソッドに渡します

PUTメソッドはPOSTメソッドとまったく同様なので、省略します。

オーバーライドの例

Form オブジェクトの検証に、画面上に表示しないデータ(例えばログインユーザ情報や settings の内容)を渡したい場合、get_form_kwargs メソッドをオーバーライドします。

from django.views.generic.edit import FormView
from myform import MyForm

class MyFormView(FormView):
    form_class = MyForm    # コンストラクタをオーバーライドしたFormクラス

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs
from django.forms.models import ModelForm

class MyForm(ModelForm):
    class Meta(ModelForm):
        model = '対象のモデルクラス'

    def __init__(self, *args, **kwargs):
        # View側のget_form_kwargsで追加したパラメータを取得する
        # ModelFormを継承する場合、モデルに定義されていないフィールド名をパラメータに受け取ると例外発生するので
        # super().__init__呼び出し前にpopして除去しておく
        self.user = kwargs.pop('user', None)
        super()__init__(*args, **kwargs)

django.views.generic.edit.CreateView

モデルインスタンスを新規に作成するためのViewです。
ソースコードはこちら

GET時のコールグラフ

CreateViewのコールグラフ(GET)

だいぶサイズが大きくなってきました。

関数名 処理内容
BaseCreateView.get 自身の object フィールドを None に初期化します。
FormMixIn.get_context_data FormViewに記述した内容です。
FormMixIn.get_form FormViewに記述した内容です。
FormMixIn.get_form_class FormViewに記述した内容です。
ModelFormMixIn.get_form_class クラスフィールド form_class を指定しなかった際に、関連付けられているモデル情報から Form オブジェクトのクラス名を生成しようとします。
FormView.get_form_kwargs FormViewに記述した内容です。
ModelFormView.get_form_kwargs FormView.get_form_kwargs に加えて、下記のキーと値を設定します。
・キー'instance' ... self.object を設定します。
FormView.get_initial FormViewに記述した内容です。
FormView.get_prefix FormViewに記述した内容です。
SingleObjectMixin.get_context_data DetailViewに記述した内容です。
ContextMixin.get_context_data TemplateViewに記述した内容です。
TemplateResponseMixin.get_template_names レンダリングするテンプレート名をリストで返します。
クラス変数 template_name の内容を返します。
TemplateResponseMixin.render_to_response テンプレートをレンダリングしてレスポンスを返します。

入力検証に使用する Form オブジェクトを生成して、指定したテンプレートをレンダリングして返します。

POST, 検証OK時のコールグラフ

POSTメソッドで、検証に使用した Form オブジェクトの is_valid メソッドが True を返す場合です。

CreateViewのコールグラフ(POST, 検証OK)

FormMixIn.get_form ~ FormView.get_prefix までの流れは GET メソッドの時と同じです。

関数名 処理内容
BaseCreateView.post 自身の object フィールドを None に初期化します。
ModelFormView.form_valid 検証用の Form オブジェクトによる検証がOKだった時に呼ばれます。
Form オブジェクトの save メソッドを呼び出し、戻り値を self.object に保持します。
FormView.form_valid FormViewに記述した内容です。
FormView.get_success_url FormViewに記述した内容です。

POST, 検証NG時のコールグラフ

POSTメソッドで、検証に使用した Form オブジェクトの is_valid メソッドが False を返す場合です。

CreateViewのコールグラフ(POST, 検証NG)

FormMixIn.get_form ~ FormView.get_prefix までの流れは GET メソッドの時と同じです。
また、FormMixIn.get_context_data 移行の流れも、GET メソッドの時と同じです。

関数名 処理内容
FormView.form_invalid 検証用の Form オブジェクトによる検証がNGだった時に呼ばれます。
get_context_data メソッドを呼び出して context を生成し、 render_to_response メソッドに渡します

オーバーライドの例

FormViewに記載した内容は、そのまま CreateView でも使えます。

django.views.generic.edit.UpdaeView

既存のモデルインスタンスを更新するためのViewです。
ソースコードはこちら

GET時のコールグラフ

UpdateViewのコールグラフ(GET)

ほとんど CreateView の GET時の処理と変わりません。
異なる部分のみ、内容を取りまとめます。

関数名 処理内容
BaseUpdateView.get 自身の object フィールドを SingleObjectMixin.get_object の戻り値で初期化します。
ここで取得したオブジェクトが更新対象となります。
SingleObjectMixin.get_object DetailViewに記述した内容です。
SingleObjectMixin.get_queryset DetailViewに記述した内容です。
ModelFormView.get_form_kwargs CreateViewと処理は同じですが、UpdateView は BaseUpdateView.get メソッドで self.object に更新対象のモデルオブジェクトを保持しています。
そのため、Form オブジェクトのコンストラクタにキー'instance'として、更新対象のモデルオブジェクトが渡ります。

POST, 検証OK時のコールグラフ

POSTメソッドで、検証に使用した Form オブジェクトの is_valid メソッドが True を返す場合です。

UpdateViewのコールグラフ(POST, 検証OK)

FormMixIn.get_form ~ FormView.get_prefix までの流れは GET メソッドの時と同じです。

関数名 処理内容
BaseUpdateView.post 自身の object フィールドを SingleObjectMixin.get_object の戻り値で初期化します。
ここで取得したオブジェクトが更新対象となります。
ModelFormView.form_valid 検証用の Form オブジェクトによる検証がOKだった時に呼ばれます。
Form オブジェクトの save メソッドを呼び出し、戻り値を self.object に保持します。
FormView.form_valid FormViewに記述した内容です。
FormView.get_success_url FormViewに記述した内容です。

POST, 検証NG時のコールグラフ

POSTメソッドで、検証に使用した Form オブジェクトの is_valid メソッドが False を返す場合です。

UpdateViewのコールグラフ(POST, 検証NG)

FormMixIn.get_form ~ FormView.get_prefix までの流れは GET メソッドの時と同じです。
また、FormMixIn.get_context_data 移行の流れも、GET メソッドの時と同じです。

関数名 処理内容
BaseUpdateView.post 自身の object フィールドを SingleObjectMixin.get_object の戻り値で初期化します。
ここで取得したオブジェクトが更新対象となります。
FormView.form_invalid 検証用の Form オブジェクトによる検証がNGだった時に呼ばれます。
get_context_data メソッドを呼び出して context を生成し、 render_to_response メソッドに渡します

オーバーライドの例

FormViewに記載した内容は、そのまま UpdateView でも使えます。

django.views.generic.edit.DeleteView

既存のモデルインスタンスを削除するためのViewです。
ソースコードはこちら
対象のモデルインスタンスを取得処理を流用するために、BaseDetailView を継承しています。
継承関係は複雑ですが、使用している処理はごくわずかです。
POSTメソッドのみサポートしています。

コールグラフ

DeleteViewのコールグラフ

関数名 処理内容
DeletionMixIn.post DeletionMixIn.delete メソッドを呼び出します。
DeletionMixIn.delete SingleObjectMixin.get_object で対象のモデルオブジェクトを取得し、delete メソッドを呼び出して削除します。
その後、get_success_url メソッドで遷移先URLを取得してリダイレクトします。
DeletionMixIn.get_success_url 削除後のリダイレクト先URLを返します。
クラスフィールド success_url が指定されている場合、その値に format(**self.object.__dict__) を実行して返します。
クラスフィールド success_url に書式指定文字列を埋めておけば、削除したモデルオブジェクトに依存したURLが生成できます。

オーバーライドの例

実際にオブジェクトを削除するのは delete メソッドです。
ここをオーバーライドすれば、論理削除が実装できます。

from django.http import HttpResponseRedirect
from django.views.generic.edit import DeleteView

class MyDeleteView(DeleteView):
    model = '対象のモデルクラス名'

    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        success_url = self.get_success_url()
        # ここで論理削除っぽい動きをする。例えば下記
        # self.object.is_deleted = True   # 削除フラグを立てる
        return HttpResponseRedirect(success_url)

参考URL