Djangoのnon_field_errors()を学習した時「フィールドが無いエラー・・・?」と誤解したことがありました(それはno_field_error(s)
ですかね)。
実際には「特定のフィールドに関連付けられていない エラーのリスト」ということですが、復習を兼ねて内容をまとめました。
今回は以下の環境で確認しています。
- Django: 4.2
- Python: 3.12
non_field_errors()
リファレンスには以下の説明があります。
このメソッドは Form.errors から、特定のフィールドに関連付けられていないエラーのリストを返します。これには、 Form.clean() で発生された ValidationError と、 Form.add_error(None, "...") で追加されたエラーが含まれます。
https://docs.djangoproject.com/ja/4.2/ref/forms/api/#django.forms.Form.non_field_errors より
他のページには以下の説明がありました。
Form.clean() をオーバーライドして発生させた例外は、特定のフィールドに結びつかない点に注意してください。これらは特別な "フィールド" (all と呼ばれます) に格納され、必要に応じて non_field_errors() メソッドを通じてアクセスできます。特定のフィールドにエラーを紐付けて格納したい場合は、add_error() を呼び出す必要があります。
https://docs.djangoproject.com/ja/4.2/ref/forms/validation/#form-and-field-validation より
注: all
となっている箇所は正確には__all__
です。はてなブログのMarkdown記法で変換されているようです。
個人的にはこちらのページの説明の方がわかりやすかったです。
実際にコードを交えてみていきます。
サンプルコード
ユーザーからの問い合わせ用のフォームとして作成しました。
clean()
メソッドでメールアドレスと確認用メールアドレスが一致しているかを確認しています。
class UserInquiryForm(forms.Form): email = forms.EmailField(max_length=30) confirm_email = forms.EmailField(max_length=30) message = forms.CharField(max_length=140) def clean(self): cleaned_data = super().clean() email = cleaned_data.get("email") confirm_email = cleaned_data.get("confirm_email") if email and confirm_email: if email != confirm_email: raise forms.ValidationError(message="メールアドレスが一致しません。") return cleaned_data
このフォームの挙動をDjangoのshell(or shell_plus)で確認します。
まずは成功例です。
バリデーションに成功(is_valid()
がTrue)していることがわかり、エラーも格納されていません。
>>> from tasks.forms import UserInquiryForm >>> example = { ... "email": "nibu@example.com", ... "confirm_email": "nibu@example.com", ... "message": "タスクが登録できません。画面を開くとエラーになります。", ... } >>> form = UserInquiryForm(example) >>> form.is_valid() True >>> form.errors {} >>> form.non_field_errors() []
では続いて、失敗例(non_field_errors()
)に格納されるケースです。
>>> from tasks.forms import UserInquiryForm >>> clean_validation_example = { ... "email": "nibu@example.com", ... "confirm_email": "nibutan@example.com", ... "message": "タスクが登録できません。画面を開くとエラーになります。", ... } >>> form = UserInquiryForm(clean_validation_example) >>> form.is_valid() False >>> form.errors {'__all__': ['メールアドレスが一致しません。']} >>> form.non_field_errors() ['メールアドレスが一致しません。']
errors
を確認すると、__all__
に格納されていることnon_field_errors()
でアクセスできること
が確認できました。
add_error() でも追加できる
最初のサンプルコードだと、forms.ValidationError
を利用して例外を発生させていましたが、add_error()
を利用することでエラーを追加することができます。
def clean(self): cleaned_data = super().clean() email = cleaned_data.get("email") confirm_email = cleaned_data.get("confirm_email") if email and confirm_email: if email != confirm_email: self.add_error(field=None, error="メールアドレスが一致しません。") return cleaned_data
この時、field=None
とすることで特定のフィールドに紐づかないようにすることができます。
今回のケースでは一致しているかどうかのチェックだけなので、forms.ValidationError
で良いと思いますが、他にもチェックするものがあればadd_error()
の方が適していそうです。
バリデーション周りは他にも色々な機能がありますが、まずはnon_field_errors()
について書いてみました。
また他のところも別の機会に書いていきます。