【Django】ModelFormのバリデーション処理の流れについて
Djangoでモデルクラスにカスタムバリデーションを実装し、
ModelFormのis_valid()
でモデルクラス側のバリデータがうまく動かないというのに悩まされたので、
フォームでモデルクラスに実装したバリデータを動かす動作を追ってみました。
バリデーションの実装方法について
Djangoは色々なバリデーション処理の実装方法があります。
Form クラスで実装
Formのclean
で実装する方法は、調べれば色々なサイトで出てきます。
モデルクラスで実装
モデルで実装する方法もありますが、こちらはあまり情報がありません。
こういうときは公式が一番です。 docs.djangoproject.com
試しに実装してみます。
Djangoに標準で入っているRegexValidatorのソースコードは下記です。 gist.github.com
__call__
メソッドで検証する値をvalue
で受け取り、検証を行いNGであれば、
raise ValidationError
で検証NGを通知します。
もし、検証結果がOKであれば何もしません。
ここから、フォームでモデルのバリデータを呼び出す処理を追っていきます。
ModelFormのバリデーション処理の流れ
今回のモデルフォーム
今回、サンプルとしてFoo
クラスのモデルフォームをを作りました。
コレを元に説明していきます。
ModelFormでis_valid()が呼ばれたら
ModelForm
Viewのpost
メソッドなりで、ModelFormのis_valid
を呼び出すと、
ModelFormのスーパークラスであるBaseForm
クラスのis_validの処理が行われます。
※ModelFormはIs_validをオーバーライドしてない
is_valid
のself.errorsはerrors
メソッドを呼び出しますが、ここでエラーがまだなければself.full_clean
メソッドをコールして検証を行います。
full_clean
メソッドのself._post_clean()
でようやくModelFormでオーバーライドされた処理に移ります。
gist.github.com
_post_clean
ですが、Modelformのinit
でinstance
を渡していなかった場合、
ModelFormのMetaクラスに設定したModelのインスタンスを生成してそれをセットしています。
そして、取得したinstanceのfull_clean
メソッドを呼び出します。
このfull_clean
はFormではなく、Modelのfull_clean
です。
ここからようやくモデルのバリデータを動かす処理に入ります。
Model
modelのfull_clean
のself.clean_fields
で各フィールドのclean
を呼び出します。
gist.github.com
CharField
はclean
メソッドをオーバーライドしていないため、Field
クラスのclean
メソッドがコールされます。
gist.github.com
clean
のrun_validators
メソッドで、実装したすべてのバリデータをコールします。
バリデータがValidationErrorを出力したらエラーメッセージに内容を追加します。
まとめ
- ModelFormの
is_valid
でモデルクラスに実装したバリデータはinstanceから呼び出される