newforms ライブラリ
| revision-up-to: | 8001 (1.0pre SVN) |
|---|
django.newforms は、 Django に新たに導入された画期的なフォーム処理ライ ブラリです。従来のフォーム/マニピュレータ/バリデータフレームワークである django.forms を置き換えるものです。このドキュメントでは、新たなフォーム ライブラリの使い方について解説します。
移行の計画
django.newforms はリリース 0.96 で新たに採り入れられた機能ですが、もう 「新しい(new)」機能ではなくなったので、将来 django.forms に名前を変更す る予定です。現在の django.forms は Django 1.0 までの間 django.oldforms という名前で利用でき、その後削除するのが適当だと考えて います。
この変更は、現在皆さんが利用しているコードの将来のバージョンに対する互換性 に直接的に関わってきます。以下の移行計画を良く読んで、それに沿ったコードを 書くようにしてください:
従来のフォームフレームワーク (現在の django.forms) は django.oldforms にコピーされています。従って、互換性のない変更を 座して待つことなく、 今すぐ コードの修正に取り掛かれます。修正は、 各アプリケーションのコードを以下のように書き換えるだけです:
from django import forms # 移行前 from django import oldforms as forms # 移行後次の Django リリース (0.97) では、現在の django.newforms を django.forms に移動します。これは互換性のない変更なので、以前の django.forms を使い続けたい人は、上記に従って import 文を変更する 必要があります。
次の Django リリース、すなわち新たな django.forms が導入されたリ リースの 後 、 0.98 か 1.0 のいずれか先に出たバージョンで、 django.oldforms をコードから除去します。
この移行計画を念頭に、 django.newforms を使う場合には以下のような import 文を使うように勧めます:
from django import newforms as forms
こうしておけば、フォームライブラリを forms モジュールとして参照でき、 django.newforms が django.forms になったときに import 文を書き 換えるだけで済みます。
「 import * 」構文を使いたければ以下のようにできます:
from django.newforms import *
上の命令は、全てのフィールド、ウィジェット、フォームクラスと検証のためのユー ティリティをローカルな名前空間に import します。便利と考える人も、美しくな いと考える人もいるでしょう。
概要
django.newforms は、以前の django.forms (「マニピュレータ」) システ ムと同じく、 HTML フォームを表示し、データ処理 (検証) を行って再表示するた めのライブラリです。HTML フォームをサーバ側で検証する場合に使います。
例えば、 Web サイトに連絡用フォームを設置し、訪問者が電子メールでメッセージ を送信できるようにしたいなら、このライブラリを使って HTML フォームフィール ドを表示し、フォームの値を検証できます。このライブラリは、 HTML の <form> タグが必要になるような状況で利用できるわけです。
このライブラリでは、以下のような概念を扱います:
- ウィジェット (Widget) -- <input type="text"> や <textarea> のような、 HTML フォームウィジェットに対応するクラスで す。ウィジェットから HTML へのレンダリングもこのクラスで行われます。
- フィールド (Field) -- データの検証を行うためのクラスです。例えば、 EmailField はデータが有効な電子メールアドレスかどうか検証します。
- フォーム (Form) -- フィールドの集まりで、データの検証や HTML への 表示方法が実装されたものです。
- メディア (Media) -- フォームをレンダするときに必要な CSS や JavaScript リソースの定義です。
このライブラリは、データベースレイヤやビュー、テンプレートといった他の Django コンポーネントに対してカップリングしていません。 newforms ライブラリ が依存しているのは settings と django.utils の二つのヘルパ関数、そして 国際化のためのフック (ただし、このライブラリを使うために国際化の機能を使わ ねばならないわけではありません) だけです。
フォームオブジェクト
newforms ライブラリの第一の用途はフォームオブジェクト (form object) の 作成にあります。フォームオブジェクトは、 django.newforms.Form クラスを サブクラス化して、フォームのフィールドを定義して作成します。フォームのフィー ルド定義は Django のデータベースモデルで親しんでいるあの記述方法で行えます。 この節では、自分のウェブサイトに「連絡フォーム (contact me)」の機能を実装す るためのフォームオブジェクトを逐次開発してゆきます。
まずは ContactForm という名前で Form のサブクラスを作成するところか らはじめましょう:
from django import newforms as forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
フォームは Field オブジェクトの組み合わせでできています。今回の例では、 subject (題名)、 message (メッセージ)、 sender (送信者)、そして cc_myself (自分に CC する)、の 4 つのフィールドをフォームに持たせます。 CharField や EmailField といったフィールド型については、また後で説 明する予定です。
Form のインスタンスを生成する
Form のインスタンスには、何らかのデータの集まりをコンストラクタに渡して 結び付けたもの (束縛 (bound) フォーム) と、そうでないもの (非束縛 (unbound) フォーム) があります。
- データと 結び付いている フォームは、データを検証機能する機能と、 フォームを HTML にレンダリングするときにデータを HTML 形式で表示する 機能をあわせ持っています。
- データと 結び付いていない フォームには検証機能はありません (検証 すべきデータがないから当然ですね!) が、空のフォームを HTML としてレン ダリングする機能は備えています。
非束縛フォームのインスタンスを生成するには、単にフォームクラスのインスタン ス化を行います:
>>> f = ContactForm()
フォームにデータを結び付けるには、データの入った辞書をフォームクラスのコン ストラクタの第一引数に渡します:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
この辞書の中では、キーは各フィールドの名前であり、フォームクラスの各属性に 対応しています。値は検証すべきデータです。通常、値は文字列にしますが、必ず しも文字列でなくてかまいません。値にどんなデータ型を指定指定できるかは、フィー ルドの型に依存します。
実行時に束縛フォームと非束縛フォームを区別したければ、フォームの is_bound 属性を調べてください:
>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({'subject': 'hello'})
>>> f.is_bound
True
空の辞書を渡すと、空のデータの入った 束縛フォーム を返します:
>>> f = ContactForm({})
>>> f.is_bound
True
束縛フォームのインスタンスに入っているデータに何らかの変更を加えたい場合や、 束縛フォームを変換して、何らかのデータの入った非束縛フォームにしたい場合に は、新たにフォームインスタンスを生成してください。フォームインスタンス内の データを変更する方法はありません。一度フォームインスタンスを生成したら、デー タの有無に関わらず、インスタンス内のデータは変更不能だと考えてください。
フォームを使ってデータを検証する
フォームオブジェクトの主要な役割はデータの検証です。束縛フォームのインスタ ンスに対して is_valid() メソッドを呼び出すと、データの検証を行って、そ の結果をブール値で返します:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
無効なデータを入れてみましょう。例えば、 subject を空にしてみます (フィールドは全てデフォルトで必須なためエラーになります)。また、 sender に不正なメールアドレス情報を入れてみます:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid e-mail address',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
errors という属性にアクセスすると、エラーメッセージの入った辞書を参照で きます:
>>> f.errors
{'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']}
この辞書は、フィールド名がキーに、エラーメッセージを表す Unicode 文字列のリ ストが値になっています。エラーメッセージがリストになっているのは、一つのフィー ルドに対して複数のエラーが存在し得るからです。
is_valid() を呼ばなくても errors にはアクセスできます。 is_valid() を呼び出すか、 errors にアクセスすると、フォームのデータ は自動的に検証されます。
errors や is_valid() に何度アクセスしても、検証のルーチンはたった 一度しか呼ばれません。別の見方をすれば、検証の処理には副作用があり、その副 作用はたった一度しか呼び出されないということです。
cleaned_data には、 Form 内で定義されている 全ての フィールドのキー と値が入ります。フォームに渡したデータに、必須でないフィールドの値が入って いない場合でもです。下の例では、データ辞書には nick_name フィールドの値 が入っていませんが、 cleaned_data には空の値が入っています:
>>> class OptionalPersonForm(Form):
... first_name = CharField()
... last_name = CharField()
... nick_name = CharField(required=False)
>>> data = {'first_name': u'John', 'last_name': u'Lennon'}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
この例で、 cleaned_data の中の nick_name は空文字列なのは、 nick_name が CharField であり、 CharField は空の値を空文字列と みなすからです。各フィールドタイプは「空の」値が設定されています。例えば、 DateField の場合、空の値は空文字列ではなく None になります。 空の値を持ったフィールドの詳しい挙動は、「組み込みフィールドクラス」の節の 各フィールドの説明中の「空のフォームデータに対する値」の項目を参照してくだ さい。
個別のフォームフィールド (フィールド名ごと) やフォーム全体 (複数フィールド の組み合わせ) に対してバリデーションを実現するコードを書けます。詳しくは、 後述の フォームやフィールドのバリデーションコードを自作する の節を参照し てください。
非束縛フォームの動作
データを含まないフォームに対して "cleaned" を実行しても無意味でしかありませ んが、参考までに非束縛フォームに対して行ったときの動作を示しておきます:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
「クリーニング済み」のデータにアクセスする
フォームクラスの各フィールドには、データの検証だけでなく、「クリーニング」 を行う役割もあります。データのクリーニングとは、データを一貫性のある書式に 正規化することです。データのクリーニングはとても素晴らしい機能で、クリーニ ングを行うと、ユーザがフィールドに色々な形式でデータを入力しても、常に一貫 性を持った出力を得られます。
例えば、 DateField はデータを Python の datetime.date オブジェクト に正規化します。フィールドの値は、 '1994-07-15' のような形式の文字列で も、 datetime.date オブジェクトでも、その他の形式でも、 DateField は有効なデータであるかぎり、常に出力を datetime.date オブジェクトで正規 化します。
データセットの入ったフォームインスタンスを生成して検証を行うと、 cleaned_data 属性を介してクリーニング済みのデータにアクセスできるようにな ります:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
Note
開発版で新たに登場した機能 cleaned_data 属性は、以前のリリース では clean_data と呼ばれていました。
CharField や EmailField のようなテキストベースのフィールドは、常に 入力を Unicode 文字列に変換します。エンコーディングに関する解説は、このドキュ メントの後の方でカバーする予定です。
データが まだ検証されていない 場合、フォームインスタンスには cleaned_data 属性がありません:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid e-mail address',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
Traceback (most recent call last):
...
AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
フォームを生成するときに追加の値を渡した場合でも、 cleaned_data の中に 入るキーは、フォーム内で定義されているフィールド だけ です。以下の例でも、 ContactForm のコンストラクタに追加のフィールドデータを渡していますが、 cleaned_data が返すのは ContactForm で定義されているフィールドだけで す:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True,
... 'extra_field_1': 'foo',
... 'extra_field_2': 'bar',
... 'extra_field_3': 'baz'}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
非束縛フォームの動作
データの入っていないフォームをクリーニングしても無意味ですが、参考までに非 束縛フォームでの挙動を示します:
>>> f = ContactForm() >>> f.cleaned_data Traceback (most recent call last): ... AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
ビューの実装例
これまでに紹介した内容をまとめる意味で、簡単な連絡フォームのビューメソッド の例を以下に示します:
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django import newforms as forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
cc_myself = forms.BooleanField()
def contact(request):
if request.POST:
f = ContactForm(request.POST)
if f.is_valid:
# ... do something with f.cleaned_data
return HttpResponseRedirect('/url/on/success/')
else:
f = ContactForm()
return render_to_response('contact.html', {'form': f})
フォームを HTML として出力する
フォームオブジェクトの二つ目の仕事は、フォームの HTML へのレンダリングです。 フォームを HTML として出力するには、フォームをインスタンス化して、 print で出力します:
>>> f = ContactForm() >>> print f <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr> <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr> <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr> <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
束縛フォームの場合、フォームのデータは適切な形で HTML 出力されます。例えば、 フィールドが <input type="text"> で表される場合、データは value 属 性の中に出力されます。フィールドが <input type="checkbox"> であれば、 必要に応じて checked="checked" が入ります:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" value="foo@example.com" /></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked="checked" /></td></tr>
デフォルトの出力は 2 カラムの HTML テーブルになり、各フィールドが一つの <tr> タグの中に収まります。以下の点に注意してください:
- 柔軟性をもたせるために、出力中には <table> と </table> タグが 入っていません。また、 <form> と </form> や、 <input type="submit"> もありません。これらのタグは自分で入れる必 要があります。
- 各フィールドタイプには、それぞれデフォルトの HTML 表現があります。 CharField や EmailField は <input type="text"> で表され、 BooleanField は <input type="checkbox"> になります。とはいえ、 これらは便利なデフォルト値にすぎません。ウィジェット (widget) を使え ば、フィールドの表現にどのような HTML を使うかを指定できます。これに ついては後で説明する予定です。
- 各タグの name 属性は ContactForm クラスの属性名から直接取り出 して使われます。
- 'Subject:', 'Message:', 'Cc myself:' といった各フィール ドのテキストラベルは、フィールド名のアンダースコアを全てスペースに変 換し、先頭の文字を大文字にして生成します。これもまたデフォルト値にす ぎず、手動でもラベルを設定できるようになっています。
- 各テキストラベルは HTML の <label> タグで囲われています。このタグ には for 属性が付いていて、対応するフォームフィールドの id 属 性に対応しています。属性の値はフィールド名の前に 'id_' を付けたも のになります。 id 属性や <label> タグはフォーム生成の定石に従っ て組み込まれているものですが、この振舞は自分で変更できます。
テーブル組みによる出力は print した時に出力されるデフォルトで、他にもい くつか出力スタイルがあります。各スタイルはフォームオブジェクトのメソッドと して利用でき、各々のレンダリングメソッドは Unicode オブジェクトを返すように なっています。
as_p()
Form.as_p() はフォームを一連の <p> タグの集まりで組みます。各 <p> タグの中に一つのフィールドが入ります:
>>> f = ContactForm() >>> f.as_p() u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>' >>> print f.as_p() <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p> <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p> <p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p> <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
form をコンテキストに入れていれば、テンプレート上では以下のようにして出 力できます:
{{ f.as_p }}
as_ul()
Form.as_ul() はフォームを一連の <li> タグで組みます。各 <li> タ グの中に一つのフィールドが入ります。 as_ul() は <ul> や </ul> を出力に 含めません 。これは、ユーザが <ul> タグの HTML 属性を好きに 指定できるようにするためです:
>>> f = ContactForm() >>> f.as_ul() u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>' >>> print f.as_ul() <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li> <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li> <li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li> <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>
form をコンテキストに入れていれば、テンプレート上では以下のようにして出 力できます:
{{ f.as_ul }}
as_table()
最後に、 Form.as_table() はフォームを <table> で組みます。これは print で出力したときに使われる形式と同じです。実際、フォームオブジェク トを print すると、背後では as_table() が呼び出されるようになってい ます:
>>> f = ContactForm() >>> f.as_table() u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>' >>> print f.as_table() <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr> <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr> <tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr> <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
form をコンテキストに入れていれば、テンプレート上では以下のようにして出 力できます:
{{ f.as_table }}
デフォルトの設定はテーブル出力なので、以下のようにしても出力できます:
{{ f }}
<label> タグの出力設定
<label> タグは、あるラベルテキストがどのフォーム要素に対応づけられてい るかを知らせるタグです。 <label> タグがあると、フォームの利便性が増し、 入力補助デバイスで操作しやすくなります。 <label> タグは常に使うようにし ておくよう勧めます。
デフォルトでは、フォームのレンダリングメソッドを呼び出すと、各フォーム要素 に id 属性が追加され、ラベルを <label> タグで囲って出力します。 id 属性の値はフォームのフィールド名の前に id_ を付けたものになりま す。とはいえ、 id 属性の命名規則を変えたり、そもそも <label> を出力 したくない人のために、この仕様は設定変更できるようになっています。
<label> タグや id の挙動を変更するには、 Form コンストラクタの auto_id 引数を使います。この引数は True 、 False 、文字列のいず れかで指定せねばなりません。
auto_id を False にすると、フォーム出力に <label> タグや id 属性が含まれなくなります:
>>> f = ContactForm(auto_id=False) >>> print f.as_table() <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /></td></tr> <tr><th>Message:</th><td><input type="text" name="message" /></td></tr> <tr><th>Sender:</th><td><input type="text" name="sender" /></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" /></li> <li>Message: <input type="text" name="message" /></li> <li>Sender: <input type="text" name="sender" /></li> <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> >>> print f.as_p() <p>Subject: <input type="text" name="subject" maxlength="100" /></p> <p>Message: <input type="text" name="message" /></p> <p>Sender: <input type="text" name="sender" /></p> <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
auto_id が True の場合、フォームの出力には <label> タグが入り、 各フォームフィールドの id 属性の値にはフィールド名をそのまま使います:
>>> f = ContactForm(auto_id=True) >>> print f.as_table() <tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" /></td></tr> <tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr> <tr><th><label for="sender">Sender:</label></th><td><input type="text" name="sender" id="sender" /></td></tr> <tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself" /></td></tr> >>> print f.as_ul() <li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></li> <li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li> <li><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></li> <li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></li> >>> print f.as_p() <p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></p> <p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p> <p><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></p> <p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></p>
auto_id がフォーマット文字 '%s' を含む文字列になっている場合、フォー ム出力は <label> タグを含むようになり、タグの id 属性はフォーマット 文字列に従って生成されます。例えば、フォーマット文字列が field_%s の場 合、 subject という名前のフィールドの id は 'field_subject' に なります。出力例は以下のようになります:
>>> f = ContactForm(auto_id='id_for_%s') >>> print f.as_table() <tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" /></td></tr> <tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr> <tr><th><label for="id_for_sender">Sender:</label></th><td><input type="text" name="sender" id="id_for_sender" /></td></tr> <tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></td></tr> >>> print f.as_ul() <li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li> <li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li> <li><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></li> <li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li> >>> print f.as_p() <p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></p> <p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p> <p><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></p> <p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></p>
auto_id がこれ以外の偽でない値、つまり %s を含まない文字列のような 値の場合、 auto_id は True に設定されたものとみなされます。
デフォルトでは、 auto_id は 'id_%s' に設定されています。
通常、フォームのレンダ時には、ラベル名の直後にコロン (:) が付加されます。 このコロンを他の文字に変更したり、文字を出力しないようにするには、 label_suffix パラメタを使います:
>>> f = ContactForm(auto_id='id_for_%s', label_suffix='') >>> print f.as_ul() <li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li> <li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li> <li><label for="id_for_sender">Sender</label> <input type="text" name="sender" id="id_for_sender" /></li> <li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li> >>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->') >>> print f.as_ul() <li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li> <li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li> <li><label for="id_for_sender">Sender -></label> <input type="text" name="sender" id="id_for_sender" /></li> <li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
ラベルの付加は、ラベルの最後の文字が区切り文字 (., !, ?, : のいずれか) でない場合にのみ行われます。
フィールドの並び順について
as_p() や as_ul(), as_table() ショートカットを使うと、各フィー ルドは Form クラス内で定義された順に出力されます。例えば、上の ContactForm の例では、フィールドの並び順は subject, message, sender, cc_myself になります。 HTML 出力の中でフィールドの並び順を 変更したければ、クラス定義内でのフィールドの並び順を変更してください。
エラーの出力方法
束縛フォームオブジェクトをレンダすると、フォームの検証がまだであればレンダ リング操作の中で自動的に検証が行われ、エラーがあれば HTML 出力中の該当フィー ルドの付近に <ul class=errorlist> でエラー内容が表示されます。エラーメッ セージ中の具体的なエラー表示位置は、どのメソッドでフォームをレンダしている かによります:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid e-mail address',
... 'cc_myself': True}
>>> f = ContactForm(data, auto_id=False)
>>> print f.as_table()
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" /></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></td></tr>
<tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul><input type="text" name="sender" value="invalid e-mail address" /></td></tr>
<tr><th>Cc myself:</th><td><input checked="checked" type="checkbox" name="cc_myself" /></td></tr>
>>> print f.as_ul()
<li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" value="Hi there" /></li>
<li><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul>Sender: <input type="text" name="sender" value="invalid e-mail address" /></li>
<li>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></li>
>>> print f.as_p()
<p><ul class="errorlist"><li>This field is required.</li></ul></p>
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" value="Hi there" /></p>
<p><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul></p>
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
エラーリストの出力形式をカスタマイズする
デフォルトでは、バリデーション時エラーの出力内容は、 django.newforms.util.ErrorList を使ってフォーマットされます。エラーの表 示に他のクラスを使いたければ、以下のようにフォームの生成時に指定します:
>>> from django.newforms.util import ErrorList >>> class DivErrorList(ErrorList): ... def __unicode__(self): ... return self.as_divs() ... def as_divs(self): ... if not self: return u'' ... return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self]) >>> f = ContactForm(data, auto_id=False, error_class=DivErrorList) >>> f.as_p() <div class="errorlist"><div class="error">This field is required.</div></div> <p>Subject: <input type="text" name="subject" maxlength="100" /></p> <p>Message: <input type="text" name="message" value="Hi there" /></p> <div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div> <p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p> <p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
より細かな出力調整
as_p() や as_ul(), as_table() といったメソッドは、単に面倒臭が りの開発者むけに用意されているショートカットでしかなく、他のやり方でもフォー ムを表示できます。
フォーム中のあるフィールドの HTML を表示するには、フォームを辞書のように扱 い、フィールドの名前をキーにして参照し、その値を出力します:
>>> f = ContactForm() >>> print f['subject'] <input id="id_subject" type="text" name="subject" maxlength="100" /> >>> print f['message'] <input type="text" name="message" id="id_message" /> >>> print f['sender'] <input type="text" name="sender" id="id_sender" /> >>> print f['cc_myself'] <input type="checkbox" name="cc_myself" id="id_cc_myself" />
フィールドを引数にして str() や unicode() を呼び出すと、レンダ結果 の HTML をそれぞれ string 型や Unicode 型のオブジェクトで返します:
>>> str(f['subject']) '<input id="id_subject" type="text" name="subject" maxlength="100" />' >>> unicode(f['subject']) u'<input id="id_subject" type="text" name="subject" maxlength="100" />'
フィールド固有の出力を行った場合でも、フォームオブジェクトの auto_id 設 定は有効です:
>>> f = ContactForm(auto_id=False) >>> print f['message'] <input type="text" name="message" /> >>> f = ContactForm(auto_id='id_%s') >>> print f['message'] <input type="text" name="message" id="id_message" />
あるフィールドに関するエラーのリストを取得するには、フィールドの errors 属性にアクセスします。このフィールドはリストライクなオブジェクトで、 HTML として出力すると <ul class="errorlist"> のリストになります:
>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
>>> f = ContactForm(data, auto_id=False)
>>> print f['message']
<input type="text" name="message" />
>>> f['message'].errors
[u'This field is required.']
>>> print f['message'].errors
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f['subject'].errors
[]
>>> print f['subject'].errors
>>> str(f['subject'].errors)
''
ビューやテンプレートでフォームを使う
では、先ほどの連絡フォームを Django のビューとテンプレートに組み込みましょ う。
簡単なビューの例
以下のビューは、デフォルトでは連絡フォームを表示し、 POST リクエストで アクセスすると、入力値の検証と処理を行います:
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# Do form processing here...
return HttpResponseRedirect('/url/on_success/')
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form})
簡単なテンプレートの例
上の例で使っているテンプレート、 contact.html は、フォームを HTML で出 力する役割を担います。フォームの出力には、前述の フォームを HTML として出力する で述べたテク ニックを使えます。
フォームを HTML 出力するもっとも簡単な方法は、以下のようにフォーム変数その ものを使うというものです:
<form method="post" action="">
<table>{{ form }}</table>
<input type="submit" />
</form>
上のテンプレートコードを使うと、フォームを form.as_table() メソッドによっ てHTML テーブルにして表示します。テーブルが表示されるのは、テンプレートシス テムがオブジェクトの __str__() 値を表示するようになっていて、 Form クラスの __str__() メソッドが自身の as_table() メソッドを呼び出すか らです。
以下のコードも全く同じ出力を生成しますが、こちらの方がより明示的です:
<form method="post" action="">
<table>{{ form.as_table }}</table>
<input type="submit" />
</form>
もちろん、 form.as_ul や form.as_p も使えます。
上の二つの例では、 <form>, <table>, <input type="submit" />, </table> および </form> といったタグが入っていることに注意してくだ さい。フォームの便宜メソッド (as_table(), as_ul() および as_p()) は、これらの HTML タグを出力しません。
複雑なテンプレート出力
これまで何度か強調してきたように、 as_table(), as_ul(), as_p() といったメソッドは、よく使う例に対するショートカットにすぎません。個々のフィー ルドを操作すれば、完全にテンプレートを制御してフォームの設計を行えます。
もっとも簡単な方法は、 {% for field in form %} を使って、フォームのフィー ルドにわたって反復処理を行うというものです。例えば:
<form method="post" action="">
<dl>
{% for field in form %}
<dt>{{ field.label_tag }}</dt>
<dd>{{ field }}</dd>
{% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
{% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
{% endfor %}
</dl>
<input type="submit" />
</form>
このような反復処理のテクニックは、各フィールドに対して同じ HTML のフォーマッ トを適用したい場合や、あらかじめフォームフィールドの名前が分からない状況で フォームを生成したい場合などに役立ちます。フィールドは Form クラスで定 義されている順番に反復処理されます。
反復処理を使う代わりに、フォームのフィールドを名前で明示した調整も行えます。 フォームフィールドを明示的に指定するには、 {{ form.fieldname }} のよう にします。 fieldname はフィールドの名前です。 例を示します:
<form method="post" action="">
<ul class="myformclass">
<li>{{ form.sender.label_tag }} {{ form.sender }}</li>
<li class="helptext">{{ form.sender.help_text }}</li>
{% if form.sender.errors %}<ul class="errorlist">{{ form.sender.errors }}</ul>{% endif %}
<li>{{ form.subject.label_tag }} {{ form.subject }}</li>
<li class="helptext">{{ form.subject.help_text }}</li>
{% if form.subject.errors %}<ul class="errorlist">{{ form.subject.errors }}</ul>{% endif %}
...
</ul>
</form>
必須のフィールドをテンプレート中でハイライト表示する
ユーザに示必須のフィールドを示すという処理は、よく行われます。以下では、上 の例を変更して、必須のフィールドの後ろにアスタリスクを挿入しています:
<form method="post" action="">
<dl>
{% for field in form %}
<dt>{{ field.label_tag }}{% if field.field.required %}*{% endif %}</dt>
<dd>{{ field }}</dd>
{% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
{% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
{% endfor %}
</dl>
<input type="submit" />
</form>
{% if field.field.required %}*{% endif %} という部分が新たに追加されて いる部分です。このコードは、フィールドが必須である場合にのみ、アスタリスク を追加します。
Django は field.required ではなく、 field.field.required をチェック しているので注意してください。テンプレート上では、 field は newforms.forms.BoundField のインスタンスであり、実際のフィールドインス タンスは field 属性の中に保持しています。
アップロードされたファイルをフォームに結びつける
開発版の Django で新たに追加された機能です
FileField や ImageField といったフィールドの入ったフォームの扱いは、 通常のフォームより少しだけ複雑です。
まず、フォームからファイルをアップロードさせるには、 <form> エレメント で enctype が "multipart/form-data" に設定されていなければなりませ ん:
<form enctype="multipart/form-data" method="post" action="/foo/">
次に、フォームを使う場合、ファイルデータをフォームに結びつけなければ なりません。ファイルデータは通常のフォームデータとは分けて扱われるので、 フォームに FileField や ImageField が入っている場合、束縛フォームを 作るには、第2引数にファイルデータを渡さねばなりません。ContactForm に mugshot という名前の ImageField を組み込んだ場合、下記のようにして、 顔写真 (mugshot) のファイルデータをフォームに結びつけます:
# 画像ファイルフィールドつきの束縛フォーム
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)}
>>> f = ContactFormWithMugshot(data, file_data)
実践的には、 request.FILES をファイルデータのソースとして指定することに なるでしょう (request.POST をフォームデータのソースにするのと同様です):
# Bound form with an image field, data from the request >>> f = ContactFormWithMugshot(request.POST, request.FILES)
非束縛フォームの構築は通常通りで、フォームデータとファイルデータの 両方 を省略します:
# Unbound form with a image field >>> f = ContactFormWithMugshot()
マルチパート形式のフォームをテストする
再利用可能なビューやテンプレートを書いているのなら、フォームがマルチパー ト形式であるかどうか前もって分からない場合もあるでしょう。 is_multipart() メソッドを使うと、フォームがマルチパート形式でエンコード されたデータの提出を要求しているかどうかを調べられます:
>>> f = ContactFormWithMugshot() >>> f.is_multipart() True
テンプレートの中では、以下のようにして使います:
{% if form.is_multipart %}
<form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
<form method="post" action="/foo/">
{% endif %}
{% form %}
</form>
フォームのサブクラス化
同じフィールドを持つようなフォームクラスをいくつも作りたい場合、サブクラス 化を用いると冗長性を排除できます。
フォームクラスをサブクラス化すると、できたフォームクラスには親クラスの全て のフィールドが入っています。サブクラスで定義したフィールドは親クラスのフィー ルドの後に続きます。
以下の例では、 ContactFormWithPriority には ContactForm の全てのフィー ルドと、 priority という追加のフィールドが入っています。 ContactForm のフィールドは先に表示されます:
>>> class ContactFormWithPriority(ContactForm): ... priority = forms.CharField() >>> f = ContactFormWithPriority(auto_id=False) >>> print f.as_ul() <li>Subject: <input type="text" name="subject" maxlength="100" /></li> <li>Message: <input type="text" name="message" /></li> <li>Sender: <input type="text" name="sender" /></li> <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> <li>Priority: <input type="text" name="priority" /></li>
複数のフォームを親クラスにしたサブクラス化も可能です。この場合、親クラスの フォームは「混ぜ込み (mix-in)」クラスのように扱われます。以下の例では、 BeatleForm が PersonForm と InstrumentForm を (この順番で) サブクラス化しています。フィールドのリストには、親クラスのフィールドが順番 に表示されます:
>>> class PersonForm(Form): ... first_name = CharField() ... last_name = CharField() >>> class InstrumentForm(Form): ... instrument = CharField() >>> class BeatleForm(PersonForm, InstrumentForm): ... haircut_type = CharField() >>> b = BeatleForm(auto_id=False) >>> print b.as_ul() <li>First name: <input type="text" name="first_name" /></li> <li>Last name: <input type="text" name="last_name" /></li> <li>Instrument: <input type="text" name="instrument" /></li> <li>Haircut type: <input type="text" name="haircut_type" /></li>
フォームのプレフィクス
Django のフォームは、一つの <form> タグの中に複数入れられます。 各々のフォームに独自の名前空間を持たせるには、 prefix キーワード引数を 使います:
>>> mother = PersonForm(prefix="mother") >>> father = PersonForm(prefix="father") >>> print mother.as_ul() <li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" /></li> <li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></li> >>> print father.as_ul() <li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li> <li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>
フィールド
フォームクラスの作成で一番重要なのは、フォームの各フィールドの定義です。各 フィールドは固有のデータ検証ロジックと、いくつかのフックが備わっています。
フィールドクラスの主な用途はフォームクラスにおけるフィールド定義ですが、フィー ルドクラスは直接インスタンス化して使えるので、フィールドの動作を理解する役 に立つはずです。各フィールドインスタンスは 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.']
Django の古いフォーム/検証フレームワークを使ったことがある人は、この VaridationError が以前の VaridationError とは別の例外であることに注 意してください。以前の例外は django.core.validators.ValidationError で すが、新たな例外は django.newforms.ValidationError です。
フィールドの主な引数
各フィールドクラスのコンストラクタは、少なくとも以下に示す引数を取ります。 フィールドクラスによっては他にもフィールド固有の引数をとりますが。ここに示 す引数はどのフィールドクラスでも 常に 指定できる引数です:
required
デフォルトでは、フィールドクラスはフィールドが必須 (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 引数を使うと、フィールドに「人間に優しい」ラベルを指定できます。 このラベルはフォーム内でフィールドを表示するときに使われます。
上の フォームを HTML として出力する で説明し たように、フィールドのデフォルトのラベルはフィールド名のアンダースコアを除 去して、頭文字を大文字にしたものです。デフォルトのラベル命名規則が期待通り のラベルを出力しない場合には、この引数を指定してください。
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
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 引数を使うと、フィールドに説明文をつけられます。 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
開発版の Django で新たに追加された機能です
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>
組み込みフォームフィールドクラス
通常、 newforms ライブラリには、一般的なバリデーション機能を備えたフィー ルドクラスのセットがついてきます。この節では、そうした組み込みフィールドに ついて述べます。
各フィールドについて、 widget パラメタを指定しなかったときのデフォルト のウィジェット型について説明しています。また、データが空の値だったとき (前述の requied の節を参照してください) に返される値についても定義して います。
BooleanField
- デフォルトのウィジェット: CheckboxInput
- 空のフォームデータに対する値: False
- Python データへの正規化: Python の True または False 値
- required=True の場合、チェックボックスがチェックされているか (値 が True であるか) 検証します。
- エラーメッセージのキー: required
開発版の Django で新たに追加された機能: CheckboxInput (および 標準の BooleanField) に空の値を指定した場合のデフォルト値は、開発版では None から False に変更されました。
Note
全てのフィールドのサブクラスにデフォルトで required=True が設定され るようになったので、バリデーション条件の設定は重要です。チェックされる 場合とされない場合のあるチェックボックスをフォームに含めたい場合は、 BooleanField を生成する際に required=False を忘れずに指定せねば なりません。
CharField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: '' (空文字列)
- Python データへの正規化: Unicode 文字列オブジェクト
- max_length または min_length が指定された場合、文字列長を検証 します。それ以外の場合、どのような入力も valid とみなします。
オプションの引数として、 max_length と min_length の二つをとれます。 これらの引数を指定すると、文字列長が最大、あるいは最小値の条件を満たしてい るか検証します。
ChoiceField
- デフォルトのウィジェット: Select
- 空のフォームデータに対する値: '' (空文字列)
- Python データへの正規化: Unicode 文字列オブジェクト
- 入力値が選択肢内にある値かどうか検証します。
- エラーメッセージのキー: required, invalid_choice
追加の引数として、 choices 引数をとります。 choices 引数はイテレー ション可能オブジェクト (たとえばリストやタプルなど) で、各要素はフィールド の選択肢として使える 2 要素のタプルでなければなりません。この引数には、モデ ルフィールドの choices 引数と同じ形式で選択肢を指定できます。詳しくは モデル API のドキュメント を参照してください。
DateField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: None
- Python データへの正規化: Python datetime.date オブジェクト
- 入力値が datetime.date や datetime.datetime オブジェクト、ま たは特定の日付フォーマットの形式に従っているか検証します。
- エラーメッセージのキー: required, invalid
オプションの引数として、 input_formats をとります。 input_formats は、文字列から有効な datetime.date オブジェクトへの変換を試みるために使 われるフォーマット文字列からなるリストです。
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'
DateTimeField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: DateTimeInput
- Python データへの正規化: Python datetime.datetime オブジェクト
- 入力値が datetime.date や datetime.datetime オブジェクト、ま たは特定の日付フォーマットの形式に従っているか検証します。
- エラーメッセージのキー: required, invalid
オプションの引数として、 input_formats をとります。 input_formats は、文字列から有効な datetime.datetime オブジェクトへの変換を試みるため に使われるフォーマット文字列からなるリストです。
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'
開発版の Django で新たに追加された機能: DateTimeField はデフォルト で TextInput を使っていましたが、変更されました。
DecimalField
開発版の Django で新たに追加された機能です
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: None
- Python データへの正規化: Python の decimal オブジェクト
- 値が 10 進小数に変換可能か検証します。文字列の先頭および末尾の空白文 字は除去されます。
- エラーメッセージのキー: required, invalid, max_value, min_value, max_digits, max_decimal_places, max_whole_digits
max_value, min_value, max_digits, および decimal_places の 4 つのオプション引数を取ります。 max_digits は最大の桁数 (先頭のゼロ詰 め桁を除いた上での小数点前後の桁数の合計) です。 decimal_places は小数 部の最大桁数です。
EmailField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: '' (空文字列)
- Python データへの正規化: Unicode 文字列オブジェクト
- やや複雑な正規表現を使って、入力値が有効なメールアドレスであるか検証 します。
- エラーメッセージのキー: required, invalid
オプションの引数として、 max_length と min_length の二つをとれます。 これらの引数を指定すると、文字列長が最大、あるいは最小値の条件を満たしてい るか検証します。
FileField
開発版の Django で新たに追加された機能です
- デフォルトのウィジェット: FileInput
- 空のフォームデータに対する値: None
- Python データへの正規化: ファイルコンテンツとファイル名を一つのオブジェ クトとしてラップする UploadedFile オブジェクト。
- フォームに結びつけられているファイルデータが空でないか検証します。
- エラーメッセージのキー: required, invalid, missing, empty
UploadedFile オブジェクトの詳細は ファイルアップロードのドキュメント を参照してください。
UploadedFile の文字列表現は filename 属性の値そのものです。
FileField をフォームで使う場合、 フォームにファイルデータを束縛する のを忘れないようにしてください。
FilePathField
開発版の Django で新たに追加された機能です
- デフォルトのウィジェット: Select
- 空のフォームデータに対する値: None
- Python データへの正規化: unicode オブジェクト
- 入力値が選択肢内にある値かどうか検証します。
- エラーメッセージのキー: required, invalid_choice
このフィールドを使うと、あるディレクトリの下にあるファイルを選択できます。 フィールドは以下の 3 つの追加引数を取ります:
引数 必須 説明 path Yes ファイルの一覧を表示したいディレクトリの絶 対パスです。実在するディレクトリを指定せね ばなりません。 recursive No False (デフォルト値) の場合、 path の直下にあるファイルのみを選択肢として表示 します。 True にすると、 path 以下 の全てのファイルを再帰的に探索して選択肢に します。 match No 正規表現です。この引数を指定すると、正規表 現にマッチしたファイル名だけを選択肢として 表示します。
FloatField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: None
- Python データへの正規化: Python の float 型
- 指定された値が浮動小数点数を表すかどうか検証します。 Python の float() 関数と同じく、前後に空白があってもかまいません。
- エラーメッセージのキー: required, invalid, max_value, min_value
オプションの引数として、 max_value および min_value をとります。こ れらの値は、入力値のとりえる値域の調整に使われます。
ImageField
開発版の Django で新たに追加された機能です
- デフォルトのウィジェット: FileInput
- 空のフォームデータに対する値: None
- Python データへの正規化: ファイルコンテンツとファイル名を一つのオブジェ クトとしてラップする UploadedFile オブジェクト。
- 空でないファイルデータがフォームに結びつけられていて、かつその内容が PIL で扱えるファイル形式であるか検証します。
- エラーメッセージのキー: required, invalid, missing, empty, invalid_image
ImageField を使いたい場合、 Python Imaging Library をインストールしてお かねばなりません。
ImageField をフォームで使う場合、 フォームにファイルデータを束縛する のを忘れないようにしてください。
IntegerField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: None
- Python データへの正規化: Python 整数型または長整数型
- 入力値が整数であるか検証します。 Python の int() 関数と同様、先頭 や末尾に空白があってもかまいません。
- エラーメッセージのキー: required, invalid, max_value, min_value
オプションの引数として、指定可能な数値の範囲を表す max_value および min_value をとります。
IPAddressField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: '' (空の文字列)
- Python データへの正規化: Unicode オブジェクト
- 正規表現を使って、値が正しい IPv4 アドレス形式であるか検証します。
- エラーメッセージのキー: required, invalid
MultipleChoiceField
- デフォルトのウィジェット: SelectMultiple
- 空のフォームデータに対する値: [] (空のリスト)
- Python データへの正規化: Unicode 文字列オブジェクトのリスト
- 入力値のリスト中の全ての値が選択肢内の値であるかどうか検証します。
- エラーメッセージのキー: required, invalid_choice, invalid_list
追加の引数として、 choices 引数をとります。 choices 引数はイテレー ション可能オブジェクト (たとえばリストやタプルなど) で、各要素はフィールド の選択肢として使える 2 要素のタプルでなければなりません。この引数には、モデ ルフィールドの choices 引数と同じ形式で選択肢を指定できます。詳しくは モデル API のドキュメント を参照してください。
NullBooleanField
- デフォルトのウィジェット: NullBooleanSelect
- 空のフォームデータに対する値: None
- Python データへの正規化: True, False または None 。
- バリデーションなし (VaridationError を送出しない)
RegexField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: '' (空文字列)
- Python データへの正規化: Unicode 文字列オブジェクト
- 入力値が特定の正規表現にマッチするかどうか検証します。
- エラーメッセージのキー: required, invalid
必須の引数 regex をとります。 regex は正規表現を表す文字列またはコ ンパイル済みの正規表現オブジェクトです。
また、以下のオプション引数をとります:
引数 説明 max_length 文字列の最大長です。 min_length 文字列の最小長です。
以前のバージョンとの互換性のため、オプション引数 error_message も指定で きるようになっています。エラーメッセージを指定したければ、 error_messages を使って、 'invalid' をキーにしたメッセージを指定す るよう薦めます。
TimeField
- デフォルトのウィジェット: TextInput
- 空のフォームデータに対する値: None
- Python データへの正規化: Python datetime.time オブジェクト
- 入力値が datetime.time オブジェクトまたは特定の日付フォーマットの 形式に従っているか検証します。
- エラーメッセージのキー: required, invalid
オプションの引数として、 input_formats をとります。 input_formats は、文字列から有効な datetime.time オブジェクトへの変換を試みるために使 われるフォーマット文字列からなるリストです。
input