@validate()

TurboGears?を使うとき、コントローラメソッドは引数をGET、POSTやCherryPyのURLメカニズムから得ます。ただ一つの弱点は、それらすべての引数は文字列であり、ふつうのPythonデータタイプに、すなわち数字は int に、日付は datetime に変換する必要があることです。

この変換機能は FormEncode? パッケージによって提供されており、メソッドで @validate() デコレータを使うことによって適用されます。FormEncodeはワンステップでバリデーションと変換の両方を提供します。何故なら変換の前にバリデーションを行ったり、バリデーションの前に変換したいようなことは頻繁にあるからです。

@validate() デコレータはウィジェットベースのフォームもふつうのCherryPy引数も評価することができます。ただし、TurboGearsを使うのに @validate() は必須ではありません。メソッドに @validate() デコレータがなければ、ただ自分で文字列変換をすればよいのです。

フォームウィジェットを使うとき

@validate() を使う一番シンプルな方法はウィジェットベースのフォームへこれを渡します:

@validate(projectname.forms.a_form)

ウィジェットシステムはデータ変換を処理するスキーマを構築することを管理し、あなたはフォームを構築するときに intdatetime オブジェクトを得ることになるでしょう。 error handling デコレータと一緒に使えば、何行かのPythonを書くことで、フォームを構築し、バリデーションを行い、エラーがあればフォームを再表示し、フォームを適切な引数へと変換することができます。

(フォームウィジェット無しに)引数のバリデーションを行う

フォームを使わない場合には話はもう少し複雑になります。このときは基本的に validators キーワード引数によって、どの引数にどのバリデータを使うかを指定する必要があります。以下はそのサンプルです:

import turbogears
from turbogears import validators, expose, validate

class Root:
    @expose(template="gs.templates.welcome")
    @validate(validators={"value": validators.Int()})
    def index(self, value=0, tg_errors=None):
        if tg_errors:
          # handle the error however you want!
        return dict(newvalue=value*2)

バリデータに渡された辞書は適切なFromEncodeバリデータのフィールド名(この例では Int )にマッピングされます。バリデーションにパスした場合は tg_errors はそのデフォルト値である None を変化させません。そこでこの値が int であるとわかるわけです。ちょっと待ってください! tg_errors って何でしょうか?

バリデーションエラーがあると、バリデーションに失敗したフィールド名をキーとした tg_errors という名前の辞書が、この関数へ渡されます。 tg_errors["value"]? のようなキーを探せば Invalid 例外オブジェクトが見つかるでしょう。 Invalid 例外オブジェクトは、それらをユーザフレンドリーなエラーメッセージにするために str() することができますし、そのエラーを処理するために、そこに含まれた情報を用いることもできます:

@expose(template="gs.templates.someform")
@validate(validators = {
        "item": validators.PlainText(), #Only letters/numbers/underscores/dashes
        "size": validators.OneOf(['S','M','L'], if_empty="M"), #Default value
        "price": validators.Money(not_empty=True) #Required field
    })
def storeitem(self, tg_errors=None, **kwargs):
    if tg_errors:
        message = [str(item) for item in tg_errors.values()]
        message = ', '.join(message)
        return dict(message=message)
    else:
        return dict(message="Success!")

FromEncode?を見てわかるように、TurboGearsはたくさんの便利なバリデータを提供しています。これらは turbogears.validators モジュールから利用できます。

ほとんどのバリデータではより強い制約のためにキーワード引数を渡すことができます。利用できるバリデータを調べるためには、 FormEncode?バリデータ モジュールと TurboGears?バリデータ モジュールの両方をチェックしてください。また独自のバリデータを作成することもできますし、既存のバリデータから構築することもできます。これに関してはFormEncodeドキュメントを参照してください。

バリデーションスキーマ

複数フィールドのバリデーションを行いときには、バリデータを再利用するか、コードをクリーンアップしてバリデーションの Schema を使うのがよいでしょう。バリデーションスキーマを作成するには turbogears.validators.Schema を継承します。そして辞書の代わりに新しく作った Schemavalidators 引数として渡します:

class MySchema(validators.Schema):
    pwd1 = validators.String(not_empty=True)
    pwd2 = validators.String(not_empty=True)
    chained_validators = [validators.FieldsMatch('pwd1', 'pwd2')]

@expose()
@validate(validators=MySchema())
def password(self, pwd1, pwd2, tg_errors=None):
    if tg_errors:
        return "There was an error"
    return "Password ok!"

このスキーマでフィールドがマッチしているのを保証している chained_validators の部分に注意してください。

繰り返しますが、 Invalid 例外オブジェクトについての情報、バリデータ、スキーマ、FormEncodeを作成することについては、 FormEncode?バリデータ ドキュメント を参考にしてください。また Formencode.validators のソースをチェックしてください。ソースを見ることはドキュメントよりはっきりしてることがよくあります。

あなたが本当にその値が必要になったとき: failsafe_values

どんな理由であれ、引数がバリデーションに失敗するとその引数からは何も値を得ることができません。

このようなときに tg_errors 辞書がいらない場合にはバリデータに if_invalid キーワード引数を渡します。

tg_errors 辞書とデフォルト値の両方を得たい場合は、 failsafe_values キーワード引数にパラメータと値のペアの辞書を渡します:

@expose()
@validate(validators=MySchema(),
          failsafe_values = {"pwd1":"swordfish"})
def password(self, pwd1, pwd2, tg_errors=None):
    if tg_errors:
        return "There was an error"
    return "Password ok!"