よくあるニーズ

この章では、 Deform を実世界のアプリケーションで使用したときに しばしば必要となる要件の解決策を収集します。

フィールドに関連付けられたデフォルトウィジェットの変更

おなじみのスキーマを改めて見てみましょう:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import colander

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Integer(),
                              validator=colander.Range(0, 200))

class People(colander.SequenceSchema):
    person = Person()

class Schema(colander.MappingSchema):
    people = People()

schema = Schema()

このスキーマは mapping オブジェクトの sequence としてレンダリングします。 それぞれの mapping は stringinteger の 2つの葉節点を持っています。 http://deformdemo.repoze.org/sequence_of_mappings/ にあるデモを試せば、それぞれのフィールドに対して実際には特定の種類の ウィジェットを指定していなくても、それに相応しいデフォルトのウィジェットが 使用されることに気がつくでしょう。これは Colander のそれぞれの デフォルト型に該当します。デフォルトでそれがどのようにマッピングされるかを 以下に示します。以下のリストの中で、見出しのスキーマ型はその直下の ウィジェットをデフォルトで使用します。

colander.Mapping
deform.widget.MappingWidget
colander.Sequence
deform.widget.SequenceWidget
colander.String
deform.widget.TextInputWidget
colander.Integer
deform.widget.TextInputWidget
colander.Float
deform.widget.TextInputWidget
colander.Decimal
deform.widget.TextInputWidget
colander.Boolean
deform.widget.CheckboxWidget
colander.Date
deform.widget.DateInputWidget
colander.DateTime
deform.widget.DateTimeInputWidget
colander.Tuple
deform.widget.Widget

Note

すべてのウィジェットが任意のスキーマ型と共に使用できるわけではありません; 各ウィジェットのドキュメンテーションには通常、そのウィジェットに対して どんな型が使用できるかが示されています。 Deform が提供する既存の ウィジェットの中に適当なものがなければ、カスタムウィジェットを使用 することができます。カスタムウィジェットを書くことについて、詳細は 独自ウィジェットを書く を参照してください。

このリストに載っていない型を含むスキーマを作成している場合や、 特定のフィールドに対して異なるウィジェットを使用したい場合、あるいは 型に関連付けられたデフォルトウィジェットの設定を変更したい場合、 「手作業で」ウィジェットにフィールドを関連付ける必要があります。 以下の節で概説されるように、それには多くの方法があります。

colander.SchemaNode コンストラクタに対する引数として

Deform 0.8 から、スキーマの一部としてウィジェットを指定することが できるようになりました:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import colander

from deform import Form
from deform.widget import TextInputWidget

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String(),
                               widget=TextAreaWidget())
    age = colander.SchemaNode(colander.Integer(),
                              validator=colander.Range(0, 200))

class People(colander.SequenceSchema):
    person = Person()

class Schema(colander.MappingSchema):
    people = People()

schema = Schema()

myform = Form(schema, buttons=('submit',))

上記の例で Person クラスの name スキーマノードに widget 引数を 渡していることに注意してください。スキーマが widget 引数を持つ スキーマノードを含む場合、 Deform によってスキーマがレンダリングされる際に ノードのコンストラクタで指定されたウィジェットが、そのノードのフォーム レンダリングに関連付けられたウィジェットとして使用されます。この場合、 name ウィジェットとして deform.widget.TextAreaWidget が 使用されます。

Note

スキーマの中で行われたウィジェットの関連付けは、 deform.Field.__setitem__()deform.Field.set_widgets() による明示的なウィジェットの割り当てによっていつでもオーバーライド されます。

ウィジェットを変更するために辞書アクセスを用いる

deform.Form コンストラクタがスキーマとともに呼び出された後で 特定のフィールドに対して使用されるウィジェットを変更することができます。 それには、問題となるフィールドに到達する辞書アクセスを用います。 deform.Form は単に deform.Field の異なる種類です。 したがって、そのメソッドはどちらの種類のオブジェクトに対しても使えます。 例えば:

1
2
3
4
5
from deform import Form
from deform.widget import TextInputWidget

myform = Form(schema, buttons=('submit',))
myform['people']['person']['name'].widget = TextInputWidget(size=10)

これは、レンダリングされたフォームの中で name という名前の String フィールドを、明示的に生成された TextInputWidget と関連付けます。 関連付けは、フィールドの構造にしたがって一連の __getitem__ 呼び出しを 行って name フィールドを見つけ、その後 name フィールドに明示的な widget 属性を設定することで行われます。

これによって、明示的なウィジェット生成に size 引数を渡して name 入力フィールドのサイズをデフォルトではなく 10em になるように することができます。

上記の例において name フィールドをデフォルトと同じ型のウィジェットに 関連付けましたが、同じパターンを使用して、簡単に name フィールドを まったく異なるウィジェットと関連付けることができます。例えば:

1
2
3
4
5
from deform import Form
from deform.widget import TextInputWidget

myform = Form(schema, buttons=('submit',))
myform['people']['person']['name'].widget = TextAreaWidget()

上記は name フィールドに対して input type=text フィールドの 代わりに HTML textarea 入力要素をレンダリングします。これは、おそらく name という名前のフィールドに対してはあまり意味がないでしょう (名前は通常は複数行の段落ではありません); しかし、それは、どのようにして 異なるウィジェットを同じフィールドに対して使用することができるかの具体例を 示します。

deform.Field.set_widgets() メソッドを用いる

同様に、フォームの複数のフィールドに複数のウィジェットを関連付けるために deform.Field.set_widgets() メソッドを使用することができます。 例えば:

1
2
3
4
5
6
from deform import Form
from deform.widget import TextInputWidget

myform = Form(schema, buttons=('submit',))
myform.set_widgets({'people.person.name':TextAreaWidget(),
                    'people.person.age':TextAreaWidget()})

deform.Field.set_widgets() に渡された辞書のそれぞれのキーは、 単一のフィールド要素に解決される “dotted name” です。辞書のそれぞれの値は ウィジェットのインスタンスです。キー名として “アスタリスク” (*) 文字と 空文字列が関係する特殊なケースを含めて、このメソッドと dotted name の解決に 関する詳細は deform.Field.set_widgets() を参照してください。

テキスト入力マスクの使用

deform.widget.TextInputWidgetdeform.widget.CheckedInputWidget ウィジェットでは、固定長の テキスト入力マスクが使えます。テキスト入力マスクを使用することによって、 テキストフィールド入力にプレースホルダーテキストが置かれ、テキスト フィールドに入力される文字の種類と長さが制限されます。

例えば:

form['ssn'].widget = TextInputWidget(mask='999-99-9999')

テキスト入力マスクを使う場合:

a はアルファベット文字を表します (A-Z,a-z)

9 は数字を表します (0-9)

* は英数字を表します (A-Z,a-z,0-9)

マスクに含まれる他のすべての文字は、マスクリテラルとみなされます。

デフォルトで、フィールド内の非リテラル文字のためのプレースホルダー テキストは _ (アンダースコア文字) になります。与えられた入力フィールド に対してこれを変更するには、 TextInputWidget の mask_placeholder 引数 を使用してください:

form['date'].widget = TextInputWidget(mask='99/99/9999',
                                      mask_placeholder="-")

マスクの例:

日付
99/99/9999
アメリカの電話番号
(999) 999-9999
アメリカの社会保障番号 (SSN)
999-99-9999

このオプションが使用される場合、マスク引数が効果を持つために、フォームを 返すページに jquery.maskedinput ライブラリをロードしなければ なりません。このライブラリのコピーは deform パッケージ自体の static/scripts ディレクトリにあります。

http://deformdemo.repoze.org/text_input_masks/ で動作する例を見てください。

テキスト入力マスクを使用することは、フィールドに対するサーバーサイドの バリデーションの代わりにはなりません; それは純粋に UI アフォーダンスです。 入力時にデータをチェックしなければならない場合、関連するスキーマノードに validator を取り付ける必要があります。

AutocompleteInputWidget の使用

deform.widget.AutocompleteInputWidget ウィジェットは、提供された 選択肢からのクライアントサイドでのテキスト入力フィールドの自動補完を 可能にします。 deform.widget.AutocompleteInputWidget ウィジェット を利用するためには、 必ず このウィジェットがレンダリングされるページで jQueryjQuery UI プラグインを有効にしなければなりません。

便宜上 jQuery UI のバージョン (autocomplete サブライブラリを含む) が deform の静的ディレクトリに含まれています。さらに、セレクション ボックスのための jQuery UI スタイルも deform static ディレクトリ に含まれています。インクルードされたライブラリをアプリケーションから 利用することについての詳細は、 レンダリングされたフォームを返す(高レベル) deform.Field.get_widget_resources() メソッド を参照してください。

deform.widget.AutocompleteInputWidget を使う非常に簡単な例は 次の通りです:

form['frozznobs'].widget = AutocompleteInputWidget(
                             values=['spam', 'eggs', 'bar', 'baz'])

values にはリストの代わりに URL を渡すことができます:

form['frobsnozz'].widget = AutocompleteInputWidget(
                             values='http://example.com/someapi')

上記の例で url がアプリケーションとは異なるホスト上にある場合、その 呼び出しは JSON 互換フォーマットあるいは JSONP 互換のレスポンスで結果を 返す必要があります。これらの構造のいずれかのようなものは JSON 形式として 適切です:

//Items are used as both value and label
['item-one', 'item-two', 'item-three']

//Separate values and labels
[
    {'value': 'item-one', 'label': 'Item One'},
    {'value': 'item-two', 'label': 'Item Two'},
    {'value': 'item-three', 'label': 'Item Three'}
]

autocomplete プラグインは、リクエスト URL に対するクエリ文字列に変数 term を追加します。それはその時点でのユーザの入力を含んでいます。 サーバは、返される結果をフィルターするためにこれを使用することができます。

詳細は、 http://api.jqueryui.com/autocomplete/#option-source - 特に source オプションに対する String 型に関する節を参照してください。

jquery.autocomplete プラグインに対するいくつかのオプションは マッピングされ、ウィジェットに渡すことができます。利用可能なオプションに 関する詳細については、 deform.widget.AutocompleteInputWidget を 参照してください。オプションの渡し方はこのようになります:

form['nobsfrozz'].widget = AutocompleteInputWidget(
                             values=['spam, 'eggs', 'bar', 'baz'],
                             min_length=1)

動作例については http://deformdemo.repoze.org/autocomplete_input/http://deformdemo.repoze.org/autocomplete_remote_input/ を参照 してください。補完データを提供する外部 URL の動作例は http://deformdemo.repoze.org/autocomplete_input_values/ で見つける ことができます。

deform.widget.AutocompleteInputWidget を使用することは、 フィールドに対するサーバーサイドのバリデーションの代わりにはなりません; それは純粋に UI アフォーダンスです。入力時にデータをチェックしなければ ならない場合、関連するスキーマノードに validator を取り付ける 必要があります。

新しいスキーマ型の作成

場合によっては Colander によって提供されるデフォルトのスキーマ型が アプリケーションのすべての構造をモデル化するのには不十分なことがあるかも しれません。

これが問題になる場合は、 Defining a New Type の Colander ドキュメンテーションを参照してください。