ポストバック

□未翻訳

□翻訳中

□翻訳完了(細田謙二)

■レビュー(中垣健志)

ポストバック

以前に使用したフォームのサブミットに関するメカニズムはとても一般的なものです。しかし、これは良いプログラミングのプラクティスではありません。すべてのインプットは検証されるべきですが、上記の例では、検証の責任が2番目のアクションにて負わされています。つまり、検証を行うアクションはフォームを生成したアクションと異なります。これは、コードの冗長性を引き起こしがちになります。

The mechanism for form submission that we used before is very common, but it is not good programming practice. All input should be validated and, in the above example, the burden of validation would fall on the second action. Thus the action that performs the validation is different from the action that generated the form. This tends to cause redundancy in the code.

フォーム送信のためのより良いパターンは、フォームを生成したアクションと同じアクションに、今回の例では"first"に、フォームをサブミットすることです。"first"アクションは、変数を受け取り、処理し、サーバーサイドに保存し、訪問者を"second"ページにリダイレクトさせます。リダイレクト先でその変数を取得します。 このメカニズムは、ポストバックと呼ばれます。

A better pattern for form submission is to submit forms to the same action that generated them, in our example the "first". The "first" action should receive the variables, process them, store them server-side, and redirect the visitor to the "second" page, which retrieves the variables. This mechanism is called a postback.

デフォルトのコントローラを自己サブミットするように変更してみましょう:

Modify the default controller to implement self-submission:

1.

2.

3.

4.

5.

6.

7.

8.

def first():

if request.vars.visitor_name:

session.visitor_name = request.vars.visitor_name

redirect(URL('second'))

return dict()

def second():

return dict()

"default/first.html"ビューは次のように変更します:

Then modify the "default/first.html" view:

1.

2.

3.

4.

5.

6.

{{extend 'layout.html'}}

What is your name?

<form>

<input name="visitor_name" />

<input type="submit" />

</form>

"default/second.html"ビューは、request.varsの代わりにsessionからデータを取得する必要があります:

and the "default/second.html" view needs to retrieve the data from the session instead of from the request.vars:

1.

2.

{{extend 'layout.html'}}

<h1>Hello {{=session.visitor_name or "anonymous"}}</h1>

訪問者から見ると、自己サブミットは、前の実装と全く同じ挙動をしています。検証はまだ加えていませんが、検証が最初のアクションで行われるようになることは明白です。

From the point of view of the visitor, the self-submission behaves exactly the same as the previous implementation. We have not added validation yet, but it is now clear that validation should be performed by the first action.

このアプローチはより優れています。なぜならまた、訪問者の名前はセッション内に留まるようになり、明示的に渡されなくてもアプリケーションのすべてのアクションとビューからアクセスできるようになるからです。

This approach is better also because the name of the visitor stays in the session, and can be accessed by all actions and views in the applications without having to be passed around explicitly.

訪問者の名前が設定される前に"second"アクションが呼び出された場合、画面上には"Hello anonymous"と表示されることに注意してください。これは、session.visitor_nameがNoneを返すからです。もう一つの方法は、コントローラ(second関数内)に次のコードを追加することです:

Note that if the "second" action is ever called before a visitor name is set, it will display "Hello anonymous" because session.visitor_name returns None. Alternatively we could have added the following code in the controller (inside the second function):

1.

2.

if not request.function=='first' and not session.visitor_name:

redirect(URL('first'))

これはコントローラに認証を強制するために使用できる一般的なメカニズムです。ただし、より強力な方法のためには第8章を参照してください。

This is a general mechanism that you can use to enforce authorization on controllers, though see Chapter 8 for a more powerful method.

web2pyではもう一歩先に進むことができ、検証を含むフォームをweb2pyに生成させることができます。web2pyはHTMLタグと同じ名前を持つヘルパー(FORM, INPUT, TEXTAREA, SELECT/OPTION)を提供します。これらを利用して、コントローラとビューのどちらにおいても、フォームを構築することができます。

With web2py we can move one step further and ask web2py to generate the form for us, including validation. web2py provides helpers (FORM, INPUT, TEXTAREA, and SELECT/OPTION) with the same names as the equivalent HTML tags. They can be used to build forms either in the controller or in the view.

例として、最初のアクションを書き換える一つの可能な方法を示します:

For example, here is one possible way to rewrite the first action:

1.

2.

3.

4.

5.

6.

7.

def first():

form = FORM(INPUT(_name='visitor_name', requires=IS_NOT_EMPTY()),

INPUT(_type='submit'))

if form.accepts(request.vars, session):

session.visitor_name = form.vars.visitor_name

redirect(URL('second'))

return dict(form=form)

ここで、FORMタグには2つのINPUTタグが含まれているのが分かります。inputタグの属性は、アンダースコアで始まる名前付きの引数で指定されます。requires引数はタグの属性ではありません(アンダースコアで始まってないからです)。これはvisitor_nameの値のためのバリデータを設定します。

where we are saying that the FORM tag contains two INPUT tags. The attributes of the input tags are specified by the named arguments starting with underscore. The requires argument is not a tag attribute (because it does not start by underscore) but it sets a validator for the value of visitor_name.

formオブジェクトは、"default/first.html"ビューにそれを埋め込むによって、簡単にHTMLとしてシリアライズすることができます。

The form object can be easily serialized in HTML by embedding it in the "default/first.html" view.

1.

2.

3.

{{extend 'layout.html'}}

What is your name?

{{=form}}

form.acceptsメソッドはバリデータを適用します。自己サブミットしたフォームが検証を通った場合、セッション内に変数が保存され、前と同じようにリダイレクトされます。フォームが検証に通らなかった場合、エラーメッセージがフォームに挿入され、次のようにユーザーに示されます:

The form.accepts method applies the validators. If the self-submitted form passes validation, it stores the variables in the session and redirects as before. If the form does not pass validation, error messages are inserted into the form and shown to the user, as below:

次節では、どのようにフォームがモデルから自動的に生成されるかを示します。

In the next section we will show how forms can be generated automatically from a model.