.. _ref-forms-validation: .. _Form and field validation: フォームやフィールドのバリデーション ===================================== :revision-up-to: 8961 (1.0) フォームのバリデーションは、データのクリーニングを行ったときに実行されます。 この挙動をカスタマイズしたければ、目的に応じていくつかの手法から選択するこ とになります。フォームの処理では、 3 つのデータクリーニング過程があります。 これらの過程は通常、フォームの ``is_valid()`` メソッドを呼び出したときに実 行されます。データのクリーニングとバリデーションをトリガする要素は他にもあ ります (``errors`` 属性へのアクセスや、 ``full_clean()`` の呼び出し) が、 通常は直接用いることはありません。 一般に、データクリーニングのメソッドは、処理中のデータに何らかの問題がある 場合、 ``ValidationError`` 例外を送出し、その際 ``ValidationError`` のコン ストラクタにエラーメッセージを渡すことになっています。 ``ValidationError`` を送出しない場合、クリーニングメソッドはクリーニング済み (正規化済み) のデー タを Python オブジェクトとして返さねばなりません。 クリーニング処理中に複数のエラーを検出し、全てのエラーをフォームのユーザに 提示したければ、 ``ValidationError`` のコンストラクタにエラーのリストを渡せ ます。 クリーニングメソッドとは、以下の 3 つです: * フィールドサブクラスの ``clean()`` メソッド。このメソッドは、該当フィー ルドクラスのインスタンスに共通して必要なクリーニングを行う役割を担いま す。例えば、 FloatField の ``clean()`` メソッドは、データを Python の ``float`` オブジェクトに変換するか、 ``ValidationError`` を送出します。 * フォームサブクラスの ``clean_()`` (```` はフォー ムフィールドを指す属性名) メソッド。このメソッドは特定の属性名のフィー ルドに対するクリーニングを行います。フィールドの型は問いません。この メソッドはパラメタ無しで呼び出されます。フィールドの値は ``self.cleaned_data`` を介して参照せねばならず、値はこの段階ではフォー ムとして提出された元の文字列ではなく、Python オブジェクトであることに 注意してください。(``cleaned_data`` に入るのは、上記の ``clean()`` メ ソッドが既にデータを一度クリーニングしているからです。) 例えば、 ``serialnumber`` という名前の ``CharField`` の中身が一意な値 になるようバリデーションを行いたければ、 ``clean_serialnumber()`` を 使うのが適切です。特定のフィールド (実際には ``CharField``) 向けでは なく、フォーム上のフィールド固有のバリデーションや、データのクリーニ ング、正規化はここで行いましょう。 * フォームのサブクラスの ``clean()`` メソッド。このメソッドは、フォーム 上の複数のフィールドに一度にアクセスする必要があるようなバリデーショ ンを実行できます。「フィールド ``A`` に値が入っている時に、フィールド ``B`` には有効なメールアドレスが入っていなければならない」といったバ リデーションにはこのメソッドを使います。このメソッドの返すデータは、 フォームの ``cleaned_data`` 属性の最終的な値になるので、このメソッド をオーバライドする場合は必ず全てのクリーニング済みデータを返すように してください (デフォルトでは、 ``Form.clean()`` は ``self.cleaned_data`` をそのまま返します)。 オーバライドされた ``Form.clean()`` の送出するエラーは特定のフィー ルドではなく、(``__all__`` という名の) 特殊な「フィールド」に関連づけ られます。エラーは ``non_field_errors()`` でアクセスできます。 上に挙げたメソッドは、各フィールドごとに一度づつ、上に挙げた順に呼び出され ます。すなわち、フォームの各フィールドについて、 (フォーム定義で宣言した順 に) まず ``Field.clean()`` メソッドを呼び出し、次いで ``cleaned_()`` 、を呼びます。最後に、 ``Form.clean()`` メソッド (オーバライドされていればそれを) を呼び出します。 先程も書いた通り、上記のメソッドは ``VaridationError`` を送出することがあり ます。個々のフィールドで、 ``Field.clean()`` メソッドが ``ValidationError`` を送出した場合、フォーム上のフィールドごとのクリーニングメソッドは呼び出さ れません。ただし、残りの全てのフィールドに対するクリーニング処理は最後まで 行われます。 フォームクラスやサブクラスに対する ``clean()`` メソッドは常に実行されます。 このメソッドが ``VaridationError`` を送出する場合、 ``cleaned_data`` は空の 辞書になります。 前の段落の意味するところは、 ``Form.clean()`` をオーバライドする場合、 ``self.cleaned_data.items()`` の各要素を調べ、さらにフォームの ``_errors`` 属性も考慮して、どのフィールドが個別のバリデーション用件を満たしているかを 調べる必要があるということです。 .. A simple example: 簡単な例 ~~~~~~~~ 入力値がカンマで区切られたメールアドレスになっていて、少なくとも一つアドレ スが入っているかどうか検証するカスタムフィールドの例を以下に示します。簡単 のため、個々のメールアドレスの検証は ``is_valid_email()`` という関数で行っ ていることにします。クラスの全体像は以下のようになります:: from django import forms class MultiEmailField(forms.Field): def clean(self, value): if not value: raise forms.ValidationError('Enter at least one e-mail address.') emails = value.split(',') for email in emails: if not is_valid_email(email): raise forms.ValidationError('%s is not a valid e-mail address.' % email) return emails 件の ``ContactForm`` の例を使って、上のカスタムフィールドをフォームで使って みます。以下のように、 ``forms.EmailField`` を ``MultiEmailField`` に置き換 えてください:: class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() senders = MultiEmailField() cc_myself = forms.BooleanField(required=False)