このドキュメントの Django のバージョンにはセキュリティ上の脆弱性があるため、すでにサポートが終了されています。新しいバージョンにアップグレードしてください!最新の Django のバージョンのドキュメントはこちら

Django v1.0 documentation

フォームやフィールドのバリデーション

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_<fieldname>() (<fieldname> はフォー ムフィールドを指す属性名) メソッド。このメソッドは特定の属性名のフィー ルドに対するクリーニングを行います。フィールドの型は問いません。この メソッドはパラメタ無しで呼び出されます。フィールドの値は 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_<fieldname>() 、を呼びます。最後に、 Form.clean() メソッド (オーバライドされていればそれを) を呼び出します。

先程も書いた通り、上記のメソッドは VaridationError を送出することがあり ます。個々のフィールドで、 Field.clean() メソッドが ValidationError を送出した場合、フォーム上のフィールドごとのクリーニングメソッドは呼び出さ れません。ただし、残りの全てのフィールドに対するクリーニング処理は最後まで 行われます。

フォームクラスやサブクラスに対する clean() メソッドは常に実行されます。 このメソッドが VaridationError を送出する場合、 cleaned_data は空の 辞書になります。

前の段落の意味するところは、 Form.clean() をオーバライドする場合、 self.cleaned_data.items() の各要素を調べ、さらにフォームの _errors 属性も考慮して、どのフィールドが個別のバリデーション用件を満たしているかを 調べる必要があるということです。

簡単な例

入力値がカンマで区切られたメールアドレスになっていて、少なくとも一つアドレ スが入っているかどうか検証するカスタムフィールドの例を以下に示します。簡単 のため、個々のメールアドレスの検証は 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.EmailFieldMultiEmailField に置き換 えてください:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    senders = MultiEmailField()
    cc_myself = forms.BooleanField(required=False)