revision-up-to: | 8961 (1.0) |
---|
フォームクラスの作成で一番重要なのは、フォームの各フィールドの定義です。各 フィールドには固有のデータ検証ロジックと、いくつかのフックが備わっています。
フィールドクラスの主な用途はフォームクラスにおけるフィールド定義ですが、フィー ルドクラスは直接インスタンス化して使えるので、フィールドの動作を理解する役 に立つはずです。各フィールドインスタンスは clean() メソッドを備えており、 単一の引数を取って検証を行い、その結果に応じて django.newforms.ValidationError を送出するか、クリーニング済みの値を返 します:
>>> f = forms.EmailField()
>>> f.clean('foo@example.com')
u'foo@example.com'
>>> f.clean(u'foo@example.com')
u'foo@example.com'
>>> f.clean('invalid e-mail address')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid e-mail address.']
各フィールドクラスのコンストラクタは、少なくとも以下に示す引数を取ります。 フィールドクラスによっては他にもフィールド固有の引数をとりますが。ここに示 す引数はどのフィールドクラスでも 常に 指定できる引数です:
デフォルトでは、フィールドクラスはフィールドが必須 (reqired) であると仮定し ています。従って、フィールドに空の値、すなわち None や空文字列 ("") を渡すと、 clean() は VaridationError 例外を送出します:
>>> f = forms.CharField()
>>> f.clean('foo')
u'foo'
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(' ')
u' '
>>> f.clean(0)
u'0'
>>> f.clean(True)
u'True'
>>> f.clean(False)
u'False'
必須で ない フィールドにするには、フィールドのコンストラクタに required=False を指定します:
>>> f = forms.CharField(required=False)
>>> f.clean('foo')
u'foo'
>>> f.clean('')
u''
>>> f.clean(None)
u''
>>> f.clean(0)
u'0'
>>> f.clean(True)
u'True'
>>> f.clean(False)
u'False'
required=False のフィールドの clean() に空の値を渡して呼び出すと、 clean() は VaridationError を送出する代わりに 正規化された 空の値 を返します。例えば CharField の場合なら、 Unicode の空文字列になります。 その他のフィールドクラスでは None になるはずです (フィールドによって異 なります)。
label 引数を使うと、フィールドに「人間に優しい」ラベルを指定できます。 このラベルはフォーム内でフィールドを表示するときに使われます。
フィールドのデフォルトのラベルはフィールド名のアンダースコアを除去して、頭 文字を大文字にしたものです。デフォルトのラベル命名規則で期待通りのラベルが 出力されない場合には、この引数を指定してください。
label を指定したフォームの例を以下に示します。出力を短くするために auto_id=False にしています:
>>> class CommentForm(forms.Form):
... name = forms.CharField(label='Your name')
... url = forms.URLField(label='Your Web site', required=False)
... comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print f
<tr><th>Your name:</th><td><input type="text" name="name" /></td></tr>
<tr><th>Your Web site:</th><td><input type="text" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
initial 引数を使うと、非束縛フォーム内でフィールドをレンダするときの初 期値を指定できます。
この引数を使うケースは、例えば以下のように、「空の」フォームの各フィールド を特定の値で初期化して表示したい場合です:
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='Your name')
... url = forms.URLField(initial='http://')
... comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url" value="http://" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
こんなことをしなくても、フォームに初期データの入った辞書を渡せばいいのにと 思うかもしれませんね。しかし、フォームにデータを渡して束縛フォームにすると、 データを表示する際に検証がトリガされてしまい、 HTML 出力にバリデーションエ ラーが入ってしまいます:
>>> class CommentForm(forms.Form):
... name = forms.CharField()
... url = forms.URLField()
... comment = forms.CharField()
>>> default_data = {'name': 'Your name', 'url': 'http://'}
>>> f = CommentForm(default_data, auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
<tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="text" name="url" value="http://" /></td></tr>
<tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr>
このため、非束縛フォームの場合に限って initial に指定した値が出力される ようになっているのです。束縛フォームの場合、出力は常に束縛済みのデータです。
また、 initial の指定値は、フィールドの値が指定されなかった場合の「フォー ルバック用の」値には ならない ので注意が必要です。 initial の値は初期 値の入ったフォームの表示 だけ に用いられます:
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='Your name')
... url = forms.URLField(initial='http://')
... comment = forms.CharField()
>>> data = {'name': '', 'url': '', 'comment': 'Foo'}
>>> f = CommentForm(data)
>>> f.is_valid()
False
# フォームの値は初期値にフォールバック *しません。*
>>> f.errors
{'url': [u'This field is required.'], 'name': [u'This field is required.']}
help_text 引数を使うと、フィールドに説明文をつけられます。 help_text を指定した場合、フォームを (as_ul() のような) フォームメ ソッドでレンダした時に、該当フィールドの隣に表示されます。
以下に、 help_text を使ったフォームの例を示します。この例では、フォーム の二つのフィールドに help_text を指定しています。出力を単純にするために、 auto_id=False を指定しています:
>>> class HelpTextContactForm(forms.Form):
... subject = forms.CharField(max_length=100, help_text='100 characters max.')
... message = forms.CharField()
... sender = forms.EmailField(help_text='A valid e-mail address, please.')
... cc_myself = forms.BooleanField(required=False)
>>> f = HelpTextContactForm(auto_id=False)
>>> print f.as_table()
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br />100 characters max.</td></tr>
<tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
<tr><th>Sender:</th><td><input type="text" name="sender" /><br />A valid e-mail address, please.</td></tr>
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
>>> print f.as_ul()
<li>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
>>> print f.as_p()
<p>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</p>
<p>Message: <input type="text" name="message" /></p>
<p>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</p>
<p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
error_messages 引数を使うと、フィールドが送出するデフォルトのメッセージ をオーバライドできます。オーバライドしたいメッセージに対応する文字列をキー とし、メッセージを値に持つ辞書を渡してください。例えば、デフォルトのメッセー ジが以下のようだったとします:
>>> generic = forms.CharField()
>>> generic.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
カスタムのエラーメッセージは以下のようにして設定します:
>>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
>>> name.clean('')
Traceback (most recent call last):
...
ValidationError: [u'Please enter your name']
各フィールドで定義されているエラーメッセージのキーは、後述の 組み込みフォームフィールドクラス の節で定義しています。
フィールドオブジェクトの initial 引数を使えばフィールドの初期値をハード コードできます。では、初期値を動的に決めたい場合はどうすればよいのでしょう。 例えば、現在ログインしているユーザで username フィールドを埋めたいよう な場合です。
動的に初期値を決めるには、フォームオブジェクトの initial 引数を使います。 この引数はフィールド名と初期値を対応づけた辞書として指定します。全てのフィー ルドを含める必要はなく、初期値を設定したいフィールドだけでかまいません。例 を示しましょう:
>>> class CommentForm(forms.Form):
... name = forms.CharField()
... url = forms.URLField()
... comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'your username'}, auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="your username" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
>>> f = CommentForm(initial={'name': 'another username'}, auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="another username" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
フィールドの initial パラメタと同じく、フォームの初期値が表示されるのは 非束縛フォームだけであり、ユーザが特定のフィールドに値を入力しなかったとき のフォールバックとしては使われません。
最後に、フィールドに initial が定義されていて、 かつ フォームの初期化 時にも initial を指定した場合、後者の initial が優先されるので気を 付けてください。例えば、以下のように、フィールドとフォームの両方に initial を指定した場合、フォームの値の方が使われます:
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='class')
... url = forms.URLField()
... comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="instance" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
通常、 forms ライブラリには、一般的なバリデーション機能を備えたフィー ルドクラスのセットがついてきます。この節では、そうした組み込みフィールドに ついて述べます。
各フィールドについて、 widget パラメタを指定しなかったときのデフォルト のウィジェット型について説明しています。また、データが空の値だったとき (前述の requied の節を参照してください) に返される値についても定義して います。
Note
全てのフィールドのサブクラスにデフォルトで required=True が設定され るようになったので、バリデーション条件の設定は重要です。チェックされる 場合とされない場合のあるチェックボックスをフォームに含めたい場合は、 BooleanField を生成する際に required=False を忘れずに指定せねば なりません。
オプションの引数が 2 つあります:
必須の引数を一つとります:
ChoiceField に似ていますが、 TypedChoiceField には coerce 引数があります。
以下の追加の引数をとります:
以下のオプションの引数をとります:
input_formats を指定しない場合、デフォルトで以下の入力フォーマットをサ ポートします:
'%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
'%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'
'%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006'
'%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006'
'%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
以下のオプションの引数をとります:
input_formats を指定しない場合、デフォルトで以下の入力フォーマットをサ ポートします:
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
'%m/%d/%y %H:%M', # '10/25/06 14:30'
'%m/%d/%y', # '10/25/06'
4 つのオプション引数を取ります:
オプションの引数として、 max_length と min_length の二つをとれます。 これらの引数を指定すると、文字列長が最大、あるいは最小値の条件を満たしてい るか検証します。
UploadedFile オブジェクトの詳細は ファイルアップロードのドキュメント を参照して ください。
FileField をフォームで使う場合、 フォームにファイルデータを束縛する のを忘れないようにしてください。
このフィールドを使うと、あるディレクトリの下にあるファイルを選択できます。 フィールドは以下の 3 つの引数を追加で取り、 path のみ必須の引数です:
オプションの引数として、 max_value および min_value をとります。こ れらの値は、入力値のとりえる値域の調整に使われます。
ImageField を使いたい場合、 Python Imaging Library をインストールしてお かねばなりません。
ImageField をフォームで使う場合、 フォームにファイルデータを束縛する のを忘れないようにしてください。
以下の二つの引数をとります:
追加の引数として choices をとります。 choices の意味は ChoiceField の choices と同じです。
追加の引数を一つ持っています:
CharField と同様、 max_length および min_length をとります。
以前のバージョンとの互換性のため、オプション引数 error_message も指定で きるようになっています。エラーメッセージを指定したければ、 error_messages を使って、 'invalid' をキーにしたメッセージを指定す るよう薦めます。
オプションの引数を一つ持っています:
input_formats を指定しない場合、デフォルトで以下の入力フォーマットをサ ポートします:
'%H:%M:%S', # '14:30:59'
'%H:%M', # '14:30'
以下のオプションの引数をとります:
以下のフィールドはまだドキュメント化されていません。
モデル間のリレーションを表現するために、二つのフィールドが提供されています。 これらのフィールドは、選択肢を QuerySet から取り出します:
これらのフィールドは、入力に応じて、フォームの cleaned_data 辞書内にモ デルオブジェクトをいれます。どちらのフィールド型にも必須の引数が一つありま す:
モデルオブジェクト一つを選択できるフィールドです。外部キーを表現するのに適 しています。
フィールドの選択肢として表示される文字列の取得には、モデルオブジェクトの __unicode__ メソッドを使います。表示をカスタマイズしたければ、 ModelChoicefield をサブクラス化して、 label_for_instance メソッドを オーバライドしてください。このメソッドはモデルオブジェクトを引数にとり、表 示に適した文字列を返さねばなりません:
class MyModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return "My Object #%i" % obj.id
複数のモデルオブジェクトを選択できるフィールドです。多対多のリレーションを 表現するのに向いています。 ModelChoiceField と同様、オブジェクトの表示 を変更するには label_from_instance メソッドをオーバライドしてください。
組み込みのフィールドクラスが用途に合わなくても、カスタムのフィールドクラス は簡単に作成できるので大丈夫です。カスタムのフィールドクラスは django.forms.Field をサブクラス化して作成します。 フィールドクラスを定義する際の制約は、 clean() メソッドを実装すること、 __init__() メソッドにコアの引数 (required, label, initial, widget, help_text) を持たせることだけです。
Aug 31, 2012