revision-up-to: | 17812 (1.4) unfinished |
---|
ウィジェットとは、Django で HTML の入力エレメントを表現するためのオブジェク トです。ウィジェットは、 HTML のレンダリングや、個々のウィジェットに対応す るデータをGET/POST 辞書から抽出する処理を行います。
フォームに何らかのフィールドを作成する場合、 Django は表示するデータの型に 応じて適切なデフォルトのウィジェットを使います。どのフィールドがどのウィ ジェットを使っているかは、 組み込みフィールドクラス のドキュメントを参照してください。
とはいえ、デフォルトとは違うウィジェットを使いたい場合もあるでしょう。その
場合には、以下の例のように、フィールドを定義する際に widget
引数を指定します:
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField(widget=forms.Textarea)
上のコードでは、 comment フィールドにデフォルトの TextInput
ウィジェッ
トではなく、より大きな Textarea
ウィジェットを使うように指定しています。
多くのウィジェットにはオプションの追加引数があり、それらはフィールドの
ウィジェットを定義する際に設定できます。次の例では、
years
属性が
SelectDateWidget
に設定されます:
from django.forms.fields import DateField, ChoiceField, MultipleChoiceField
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.extras.widgets import SelectDateWidget
BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'))
FAVORITE_COLORS_CHOICES = (('blue', 'Blue'),
('green', 'Green'),
('black', 'Black'))
class SimpleForm(forms.Form):
birth_year = DateField(widget=SelectDateWidget(years=BIRTH_YEAR_CHOICES))
gender = ChoiceField(widget=RadioSelect, choices=GENDER_CHOICES)
favorite_colors = forms.MultipleChoiceField(required=False,
widget=CheckboxSelectMultiple, choices=FAVORITE_COLORS_CHOICES)
どのようなウィジェットが利用可能で、それらがどの引数を受け付けるかについては、 組み込みウィジェット を参照してください。
Select
ウィジェットを継承するウィジェットは選択肢を扱います。これらは
選ぶことのできるオプション一覧をユーザに提示します。ウィジェットによって
オプション一覧の提示方法は異なります。 Select
ウィジェットは HTML の
<select>
を、 RadioSelect
はラジオボタンを使う、という具合です。
Select
ウィジェットはデフォルトで ChoiceField
フィールド
によって使われます。このウィジェットは表示する選択肢を ChoiceField
から継承しており、 ChoiceField.choices
を変更すると
Select.choices
も更新されます。例えば:
>>> from django import forms
>>> CHOICES = (('1', 'First',), ('2', 'Second',)))
>>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
>>> choice_field.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices = ()
>>> choice_field.choices = (('1', 'First and only',),)
>>> choice_field.widget.choices
[('1', 'First and only')]
choices
属性を持つウィジェットは、実は選択肢を扱わないフィールド
– 例えば CharField
– に対して使うことも可能ですが、本質的にその
選択肢がモデル由来であり、かつ表示目的だけのウィジェットでもないならば、
ChoiceField
ベースのフィールドに対して使うことを推奨します。
ウィジェットを HTML としてレンダリングする際、 Django は最小限の HTML しか
出力しません。すなわち、クラス定義やウィジェット固有の属性は一切付加しない
のです。従って、例えばページ上にまったく同じ見栄えの TextInput
ウィジェットが並ぶわけです。
ウィジェットごとに見栄えを変えたいのなら、各々のウィジェットに属性を指定し てやる必要があります。ウィジェットを指定するときに、レンダリング後の HTML に付加したい属性のリストを指定できます。
例えば、以下のような簡単なフォームを考えましょう:
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
comment = forms.CharField()
このフォームは 3 つの TextInput
ウィジェットからなり、デフォルトの
レンダリングでは CSS クラスや属性は指定されていません。従って、各ウィジェットは
全く同じ入力ボックスとしてレンダリングされます:
>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" /></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>
現実の Web ページでは、全ウィジェットが同じに見えるような見栄えを期待しない
でしょう。コメント欄をもうちょっと大きな入力ボックスにしたかったり、
'name'
ウィジェットに特別な CSS クラスを指定したかったりするかもしれま
せん。そうするには、ウィジェット作成時に Widget.attrs
属性を使用します:
例えば:
class CommentForm(forms.Form):
name = forms.CharField(
widget=forms.TextInput(attrs={'class':'special'}))
url = forms.URLField()
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
これで、 Django はレンダリング結果に追加の属性を組み込むようになります:
>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
Django は、基本的な HTML ウィジェットすべてと、よく使われるウィジェットグルー プを提供しています:
Widget
¶PasswordInput
¶ClearableFileInput
¶ClearableFileInput
¶リリースノートを参照してください
フィールドが入力必須ではなく、かつ初期データがある場合に、フィールドの値を
クリアするためのチェックボックスを備えたファイルアップロード入力:
<input type='file' ...>
です。
DateInput
¶DateTimeInput
¶TimeInput
¶CheckboxInput
¶Select
¶SelectMultiple
¶RadioSelect
¶RadioSelect
¶Select
と似ていますが、 <li>
タグを使ったラジオボタンのリスト
としてレンダリングされます:
<ul>
<li><input type='radio' ...></li>
...
</ul>
リリースノートを参照してください
生成されるマークアップをもっと細かくコントロールしたければ、テンプレート内で
ラジオボタンに対してループを回すことができます。仮に myform
という
フォームがあり、そこに RadioSelect
をウィジェットに指定した beatles
というフィールドがあると仮定すると:
{% for radio in myform.beatles %}
<div class="myradio">
{{ radio }}
</div>
{% endfor %}
これは次の HTML を生成します:
<div class="myradio">
<label><input type="radio" name="beatles" value="john" /> John</label>
</div>
<div class="myradio">
<label><input type="radio" name="beatles" value="paul" /> Paul</label>
</div>
<div class="myradio">
<label><input type="radio" name="beatles" value="george" /> George</label>
</div>
<div class="myradio">
<label><input type="radio" name="beatles" value="ringo" /> Ringo</label>
</div>
<label>
タグに囲まれていますね。さらに細かくコントロールしたければ、
ラジオボタンごとの tag
と choice_label
属性を使えます。例えば
このテンプレート...
{% for radio in myform.beatles %}
<label>
{{ radio.choice_label }}
<span class="radio">{{ radio.tag }}</span>
</label>
{% endfor %}
...は次の HTML になります:
<label>
John
<span class="radio"><input type="radio" name="beatles" value="john" /></span>
</label>
<label>
Paul
<span class="radio"><input type="radio" name="beatles" value="paul" /></span>
</label>
<label>
George
<span class="radio"><input type="radio" name="beatles" value="george" /></span>
</label>
<label>
Ringo
<span class="radio"><input type="radio" name="beatles" value="ringo" /></span>
</label>
もしラジオボタンに対してループを回さない – つまり単純にテンプレートで
{{ myform.beatles }}
と書く – と決めたなら、上に記した通り、
それらは <li>
タグを使った <ul>
の中に出力されることになるでしょう。
CheckboxSelectMultiple
¶CheckboxSelectMultiple
¶SelectMultiple
と似ていますが、チェックボックスのリストとして
レンダリングされます:
<ul>
<li><input type='checkbox' ...></li>
...
</ul>
MultiWidget
¶MultiWidget
¶複数のウィジェットをラップするウィジェットです。おそらく
MultiValueField
と共に使いたくなるでしょう。
これの render()
メソッドは、どうやって一つの値を複数のウィジェットで
表示するかを決める必要があるため、他のウィジェットのものとは異なります。
これのサブクラスは format_output
メソッドを独自に実装しているかも
しれません。 format_output
メソッドは、レンダリングされたウィジェットの
リストを受け取って、それらを自由に書式化し、 HTML の文字列を返します (訳注:
format_output メソッドはウィジェットのレンダリング結果をカスタマイズする
フックです)。
レンダリング時に使われる引数 value
は次の 2 つのいずれかになります:
list
。list
を「圧縮」表現した一つの値 (例えば文字列) 。2 つ目の場合 – すなわちリスト ではない 場合 – render()
はまず
レンダリングする前に値を list
に展開します。これは、
MultiWidget
のサブクラスが実装しなければならない decompress()
メソッドを呼ぶことで行われます。このメソッドは一つの「圧縮」された値を
受け取り、list
を返します。一例として、
SplitDateTimeWidget
がどうやって datetime
の値を
日付と時刻という 2 つの値に分離したリストに変換しているかを挙げましょう:
class SplitDateTimeWidget(MultiWidget):
# ...
def decompress(self, value):
if value:
return [value.date(), value.time().replace(microsecond=0)]
return [None, None]
render()
が HTML レンダリングを実行するとき、リスト中の各値は対応する
ウィジェットを使ってレンダリングされます – 最初の値は最初のウィジェットで、
2 つ目の値は 2 つ目のウィジェットで、という具合です。
MultiWidget
は 1 つ指定必須の引数があります:
widgets
¶必要なウィジェットを含んだイテレーション可能オブジェクト。
SplitDateTimeWidget
¶SplitDateTimeWidget
¶日付用の DateInput
と、時刻用の TimeInput
を、
MultiWidget
を使ってラップしたものです。
SplitDateTimeWidget
には 2 つオプションの属性があります:
date_format
¶DateInput.format
と似ています。
time_format
¶TimeInput.format
と似ています。
Oct 26, 2017