SQLFORM

□未翻訳

□翻訳中

■翻訳完了(細田謙二)

■レビュー(Omi Chiba)

SQLFORM

次の段階に進んで、以下のようなアプリケーションのモデルファイルを用意します:

We now move to the next level by providing the application with a model file:

1.

2.

db = DAL('sqlite://storage.sqlite')

db.define_table('person', Field('name', requires=IS_NOT_EMPTY()))

コントローラを以下のように変更します:

Modify the controller as follows:

1.

2.

3.

4.

5.

6.

7.

8.

9.

def display_form():

form = SQLFORM(db.person)

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

response.flash = 'form accepted'

elif form.errors:

response.flash = 'form has errors'

else:

response.flash = 'please fill out the form'

return dict(form=form)

ビューを変更する必要はありません。

The view does not need to be changed.

コントローラでは、FORMを構築する必要はありません。なぜなら、SQLFORMは、モデルに定義されたdb.personテーブルからそれを構築するからです。この新しいフォームがシリアライズされると次のように表示されます:

In the new controller, you do not need to build a FORM, since the SQLFORM constructor built one from the table db.person defined in the model. This new form, when serialized, appears as:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

<form enctype="multipart/form-data" action="" method="post">

<table>

<tr id="person_name__row">

<td><label id="person_name__label"

for="person_name">Your name: </label></td>

<td><input type="text" class="string"

name="name" value="" id="person_name" /></td>

<td></td>

</tr>

<tr id="submit_record__row">

<td></td>

<td><input value="Submit" type="submit" /></td>

<td></td>

</tr>

</table>

<input value="9038845529" type="hidden" name="_formkey" />

<input value="person" type="hidden" name="_formname" />

</form>

この自動的に生成されたフォームは、前述の低レベルのフォームよりも複雑です。第1に、これはテーブルの行を含み、各行は3つのカラムを持っています。最 初のカラムはフィールドの名前を保持しています(db.personから決定されます)。第2のカラムは入力フィールドを保持します(最終的にエラーメッ セージも保持します)。第3のカラムは省略可能で空になっています(SQLFORMのコンストラクタにおいてフィールドを用いて入力される可能性がありま す)。

The automatically generated form is more complex than the previous low-level form. First of all, it contains a table of rows, and each row has three columns. The first column contains the field labels (as determined from the db.person), the second column contains the input fields (and eventually error messages), and the third column is optional and therefore empty (it can be populated with the fields in the SQLFORM constructor).

フォームのすべてのタグには、テーブルとフィールドの名前に由来する名前が付けられています。これによりCSSとJavaScriptを用いてフォームをカスタマイズするのが容易になります。この機能については、第10章で詳しく説明します。

All tags in the form have names derived from the table and field name. This allows easy customization of the form using CSS and JavaScript. This capability is discussed in more detail in Chapter 10.

ここでより重要なのは、acceptsメソッドがより多くの仕事をすることです。前回の場合と同様、入力の検証を行いますが、加えて、入力が検証を通ったら、データベースに対して新規レコードの挿入を実行し、form.vars.idに新規レコードのユニークな"id"を格納します。

More important is that now the accepts method does a lot more work for you. As in the previous case, it performs validation of the input, but additionally, if the input passes validation, it also performs a database insert of the new record and stores in form.vars.id the unique "id" of the new record.

SQLFORM オブジェクトはまた、自動的に"upload"フィールドを処理し、アップロードしたファイルを"uploads"フォルダに保存します(競合を避けるた め安全にリネームして、ディレクトリ・トラバーサル攻撃を防いだ後に保存します)。そして、(新しい)ファイル名をデータベースの適切なフィールドに保存 します。

A SQLFORM object also deals automatically with "upload" fields by saving uploaded files in the "uploads" folder (after having them renamed safely to avoid conflicts and prevent directory traversal attacks) and stores their names (their new names) into the appropriate field in the database.

SQLFORM は、"boolean"の値をチェックボックスで、"text"の値をテキストエリアで、限定したセットまたはデータベース内に含まれることを要求された値をドロップボックスで、"upload"フィールドをアップロードしたファイルをダウンロードできるようにしたリンクで、表示します。"blob"フィールドは非表示します。後述しますが、異なる方法で処理されることになるからです。

A SQLFORM displays "boolean" values with checkboxes, "text" values with textareas, values required to be in a definite set or a database with drop-boxes, and "upload" fields with links that allow users to download the uploaded files. It hides "blob" fields, since they are supposed to be handled differently, as discussed later.

たとえば、次のモデルを考えてください:

For example, consider the following model:

1.

2.

3.

4.

5.

6.

db.define_table('person',

Field('name', requires=IS_NOT_EMPTY()),

Field('married', 'boolean'),

Field('gender', requires=IS_IN_SET(['Male', 'Female', 'Other'])),

Field('profile', 'text'),

Field('image', 'upload'))

この場合、SQLFORM(db.person)は次に表示されるようなフォームを生成します:

In this case, SQLFORM(db.person) generates the form shown below:

SQLFORM のコンストラクタは、さまざまなカスタマイズを可能にします。たとえば、フィールドの一部のみを表示したり、ラベルを変更したり、オプション的な第3のカ ラムに値を加えたり、現在のINSERTフォームとは対照的にUPDATEとDELETEフォームを作成したりすることができます。SQLFORMはweb2pyにおいて、最も大きく時間を節約する単一のオブジェクトです。

The SQLFORM constructor allows various customizations, such as displaying only a subset of the fields, changing the labels, adding values to the optional third column, or creating UPDATE and DELETE forms, as opposed to INSERT forms like the current one. SQLFORM is the single biggest time-saver object in web2py.

SQLFORMクラスは"gluon/sqlhtml.py"に定義されています。これは、xmlメソッドをオーバライドして簡単に拡張することができます。このメソッドはこのオブジェクトをシリアライズして、その出力を変更します。

The class SQLFORM is defined in "gluon/sqlhtml.py". It can be easily extended by overriding itsxml method, the method that serializes the objects, to change its output.

SQLFORMのコンストラクタの用法は以下の通りです:

The signature for the SQLFORM constructor is the following:

1.

2.

3.

4.

5.

6.

SQLFORM(table, record=None, deletable=False,

linkto=None, upload=None, fields=None, labels=None, col3={},

submit_button='Submit', delete_label='Check to delete:',

id_label='Record id: ', showid=True,

readonly=False, comments=True, keepopts=[],

ignore_rw=False, formstyle='table3cols',**attributes)

  • オプション的な第2の引数は、INSERTフォームから、指定したレコードに対するUPDATEフォームに切り替えます(次の小節を参照してください)。

  • The optional second argument turns the INSERT form into an UPDATE form for the specified record (see next subsection).

  • deletableがTrueの場合、UPDATEフォームは"Chceck to delete"というチェックボックスを表示します。フィールドがある場合、このラベルの値はdelete_label引数を介して設定されます。

  • If deletable is set to True, the UPDATE form displays a "Check to delete" checkbox. The value of the label if this field is set via the delete_label argument.

  • submit_buttonはサブミット・ボタンの値を設定します。

  • submit_button sets the value of the submit button.

  • id_labelはレコードの"id"のラベルを設定します。

  • id_label sets the label of the record "id"

  • showidがFalseの場合、レコードの"id"は表示されません。

    • The "id" of the record is not shown if showid is set to False.

  • fieldsは表示したいフィールド名のオプション的なリストです。リストが提供されている場合、リスト内のフィールドしか表示されません。例:

  • fields is an optional list of field names that you want to display. If a list is provided, only fields in the list are displayed. For example:

1.

fields = ['name']

  • labelsはフィールドラベルの辞書です。辞書のキーはフィールド名で、対応する値はラベルとして表示されるものです。ラベルが提供されていない場合、web2pyはラベルをフィールド名から生成します(フィールド名を大文字で書き始めアンダースコアをスペースに置換します)。例:

  • labels is a dictionary of field labels. The dictionary key is a field name and the corresponding value is what gets displayed as its label. If a label is not provided, web2py derives the label from the field name (it capitalizes the field name and replaces underscores with spaces). For example:

1.

labels = {'name':'Your Full Name:'}

  • col3は第3のカラム用の辞書の値です。例:

  • col3 is a dictionary of values for the third column. For example:

1.

2.

col3 = {'name':A('what is this?',

_href='http://www.google.com/search?q=define:name')}

  • linktoとuploadは、ユーザー定義コントローラへのオプション的なURLです。これにより、フォームで参照フィールドを扱うことが可能になります。これについては、後述の節で詳説します。

  • linkto and upload are optional URLs to user-defined controllers that allow the form to deal with reference fields. This is discussed in more detail later in the section.

  • readonly。Trueの場合、読み取り専用のフォームを表示します

  • readonly. If set to True, displays the form as readonly

  • comments。Falseの場合、col3のコメントを表示しません。

  • comments. If set to False, does not display the col3 comments

  • ignore_rw。通常は、作成/更新フォームに対して、writable=Trueでマークされたフィールドしか表示されず、読み取り専用フォーmに対しては、readable=Trueでマークしたフィールドしか表示されません。ignore_rw=Trueに設定すると、これらの制約は無視され、すべてのフィールドが表示されます。これは主に、appadmineインターフェースにおいて。モデルの意図を覆して、各テーブルのすべてのフィールドを表示するために使用されます。

  • ignore_rw. Normally, for a create/update form, only fields marked as writable=True are shown, and for readonly forms, only fields marked as readable=True are shown. Setting ignore_rw=True causes those constraints to be ignored, and all fields are displayed. This is mostly used in the appadmin interface to display all fields for each table, overriding what the model indicates.

  • formstyleフォームをhtmlにシリアライズするときに使用されるスタイルを決めます。次の値をとることができます:"table3cols"(デフォルト)、"table2cols"(一行にラベルとコメントを、もう1つの行に入力を表示します)、"ul"(入力フィールドの順序なしリストを作成します)、"divs"(フォームをcssフレンドリなdivで表現します)。 formstyleはまた、(record_id, field_label, field_widget, field_comment)を属性として受け取り、TR()オブジェクトを返す関数をとることもできます。

  • formstyle determines the style to be used when serializing the form in html. It can be "table3cols" (default), "table2cols" (one row for label and comment, and one row for input), "ul" (makes an unordered list of input fields), "divs" (represents the form using css friendly divs, for arbitrary customization). formstyle can also be a function that takes (record_id, field_label, field_widget, field_comment) as attributes and returns a TR() object.

  • オプション的なattributesは、SQLFORMオブジェクトをレンダリングするFORMタグに対して渡したいアンダースコアで始まる引数群です。たとえば次のようになります:

    • Optional attributes are arguments starting with underscore that you want to pass to the FORM tag that renders the SQLFORM object. Examples are:

1.

2.

_action = '.'

_method = 'POST'

特別なhidden属性があります。辞書がhiddenとして渡されたとき、その項目は"hidden"INPUTフィールドに変換されます(第5章のFORMヘルパの例を参照してください)。

There is a special hidden attribute. When a dictionary is passed as hidden, its items are translated into "hidden" INPUT fields (see the example for the FORM helper in Chapter 5).

SQLFORMinsert/update/delete

SQLFORM and insert/update/delete

SQLFORMはフォームが受理されたとき新規のdbレコードを作成します。以下のものを仮定すると

SQLFORM creates a new db record when the form is accepted. Assuming

1.

form=SQLFORM(db.test)

最後の作成したレコードのidはmyform.vars.idでアクセスできます。

, then the id of the last-created record will be accessible in myform.vars.id.

レコードを第2のオプション引数としてSQLFORMのコンストラクタに渡した場合、フォームは、そのレコードのためのUPDATEフォームになります。これは、フォームがサブミットされたとき、既存のレコードがアップロードされ、どの新規のレコードも作成されないことを意味します。deletable=Trueとして引数を設定すると、UPDATEフォームは"check to delete"というチェックボックスを表示します。これがチェックされていると、レコードは削除されます。

If you pass a record as optional second argument to the SQLFORM constructor, the form becomes an UPDATE form for that record. This means that when the form is submitted the existing record is updated and no new record is inserted. If you set the argumentdeletable=True, the UPDATE form displays a "check to delete" checkbox. If checked, the record is deleted.

たとえば、前述の例のコントローラを修正し、次のように、URLのパスにおけて追加の整数引数を渡すことができます。

You can, for example, modify the controller of the previous example so that when we pass an additional integer argument in the URL path, as in:

1.

/test/default/display_form/2

これに対応するidを持つレコードがあると、SQLFORMは、このレコードのためのUPDATE/DELETEフォームを生成します:

and if there is a record with the corresponding id, the SQLFORM generates an UPDATE/DELETE form for the record:

1.

2.

3.

4.

5.

6.

7.

8.

def display_form():

record = db.person(request.args(0)) or redirect(URL('index'))

form = SQLFORM(db.person, record)

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

response.flash = 'form accepted'

elif form.errors:

response.flash = 'form has errors'

return dict(form=form)

2行目でレコードを見つけ、3行目でUPDATE/DELETEフォームを作っています。4行目はすべての対応するフォームの処理を行います。

Line 2 finds the record and line 3 makes an UPDATE/DELETE form. Line 4 does all the corresponding form processing.

更新フォームは作成フォームにとても似ていますが、現在のレコードによって事前入力され、プレビュー画像も表示します。デフォルトでは、deletable=Trueになっていて、"delete record"オプションが更新フォームに表示されます。

An update form is very similar to a create form except that it is pre-populated with the current record and it previews images. By defaultdeletable = True which means the update form will display a "delete record" option.

編集フォームはまた、name="id"という隠れINPUTフィールドを保持しています。これによりレコードが特定できるようになります。このidはまた、追加のレキュリティのためサーバーサイドで保存され、訪問者がフィールドの値を改ざんした場合、UPDATEは実行されず、web2pyは"user is tampering with form"となるSyntaxErrorを発生させます。

Edit forms also contain a hidden INPUT field with name="id" which is used to identify the record. This id is also stored server-side for additional security and, if the visitor tampers with the value of this field, the UPDATE is not performed and web2py raises a SyntaxError, "user is tampering with form".

Fieldがwritable=Falseとしてマークされていると、フィールドは作成フォームに表示されず、読み込み専用の更新フォームで表示されます。フィールドがwritable=False、かつ、readable=Falseとしてマークされていて場合、フィールドは、更新フォームを含めすべてにおいて表示されません。

When a Field is marked with writable=False, the field is not shown in create forms, and it is is shown readonly in update forms. If a field is marked as writable=False and readable=False, then the field is not shown at all, not even in update forms.

次のように作成されたフォームは、

Forms created with

1.

form = SQLFORM(...,ignore_rw=True)

readableとwritableの属性を無視して、常にすべてのフィールドを表示します。appadminのフォームはデフォルトでそれらを無視します。

ignore the readable and writable attributes and always show all fields. Forms in appadminignore them by default.

次のように作成されたフォームは、

Forms created with

1.

form = SQLFORM(table,record_id,readonly=True)

常に、読み取り専用モードですべてのフィールドを表示し、受理することはありません。

always show all fields in readonly mode, and they cannot be accepted.

HTMLにおけるSQLFORM

SQLFORM in HTML

SQLFORMのフォームをその生成と処理機能から利便を享受するために使用したいが、SQLFORMオブジェクトのパラメタでは達成できなくらいのHTMLのカスタマイズが必要で、HTMLを用いてフォームを設計しなければならないことがあります。

There are times when you want to use SQLFORM to benefit from its form generation and processing, but you need a level of customization of the form in HTML that you cannot achieve with the parameters of the SQLFORM object, so you have to design the form using HTML.

では、前回のコントローラを編集し新しいアクションを追加してみます:

Now, edit the previous controller and add a new action:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

def display_manual_form():

form = SQLFORM(db.person)

if form.accepts(request.vars, formname='test'):

response.flash = 'form accepted'

elif form.errors:

response.flash = 'form has errors'

else:

response.flash = 'please fill the form'

# Note: no form instance is passed to the view

return dict()

そして、関連付けられたビュー"default/display_manual_form.html"にフォームを挿入します:

and insert the form in the associated "default/display_manual_form.html" view:

1.

2.

3.

4.

5.

6.

7.

8.

{{extend 'layout.html'}}

<form>

<ul>

<li>Your name is <input name="name" /></li>

</ul>

<input type="submit" />

<input type="hidden" name="_formname" value="test" />

</form>

ここで、アクションはフォームを返していないことに注意してください。なぜならビューに渡されないからです。ビュー はHTMLにおいて手動で作成されたフォームを含んでいます。フォームは、隠れフィールド"_formname"を含んでいて、それはアクションの acceptsの引数で指定されたformnameと必ず同じにしなければなりません。web2pyは同じページに複数のフォームがある場合に、どれから サブミットされたかを判断するのに、フォームの名前を使用します。ページが単一のフォームからなる場合、formname=Noneと設定して、ビューにおける隠れフィールドを見送ることができます。

Notice that the action does not return the form because it does not need to pass it to the view. The view contains a form created manually in HTML. The form contains a hidden field "_formname" that must be the same formname specified as an argument of accepts in the action. web2py uses the form name in case there are multiple forms on the same page, to determine which one was submitted. If the page contains a single form, you can setformname=None and omit the hidden field in the view.

form.acceptsはresponse.varsの内部から、データベースのdb.personテーブルにおけるフィールドと照合するデータを探します。これらのフィールドはHTMLにおいて以下の形式で宣言されています

form.accepts will look inside response.vars for data that matches fields in the database tabledb.person. These fields are declared in the HTML in the format

1.

<input name="field_name_goes_here" />

この例が与えられたとき、フォームの変数は引数としてURLに伝えられることに注意してください。 こうしたくない場合、POSTプロトコルを指定する必要があります。さらに注意として、アップロードフィールドが指定されている場合、フォームはこれを許可するように設定しておく必要があります。以下に、両方のオプションを表示します:

Note that in the example given, the form variables will be passed on the URL as arguments. If this is not desired, the POST protocol will have to be specified. Note furthermore, that if upload fields are specified, the form will have to be set up to allow this. Here, both options are shown:

1.

<form enctype="multipart/form-data" method="post">

SQLFORMとアップロード

SQLFORM and Uploads

"upload"型のフィールドは特殊です。それらは、type="file"のINPUTフィールドでレンダリングされます。特に指定がない限り、アップロードしたファイルはバッファにストリームされ、自動的に割り当てられる新しい安全な名前を用いて、アプリケーションの"upload"フォルダに保存されます。このファイルの名前はこのとき、アップロード型のフィールドに保存されます。

Fields of type "upload" are special. They are rendered as INPUT fields of type="file". Unless otherwise specified, the uploaded file is streamed in using a buffer, and stored under the "uploads" folder of the application using a new safe name, assigned automatically. The name of this file is then saved into the field of type uploads.

例として、次のモデルを考えてください:

As an example, consider the following model:

1.

2.

3.

db.define_table('person',

Field('name', requires=IS_NOT_EMPTY()),

Field('image', 'upload'))

上記のコントローラのアクション"display_form"と同じものを利用することができます。

You can use the same controller action "display_form" shown above.

新規のレコードを挿入するとき、フォームはファイルに対する閲覧を可能にします。たとえば、jpg画像を選択してください。このファイルはアップロードされ、次のように保存されます:

When you insert a new record, the form allows you to browse for a file. Choose, for example, a jpg image. The file is uploaded and stored as:

1.

applications/test/uploads/person.image.XXXXX.jpg

"xxxxxx"は、web2pyによってこのファイルに割り当てられるランダムな識別子になります。

"XXXXXX" is a random identifier for the file assigned by web2py.

デフォルトでは、アップロードしたファイルの元のファイル名はb16エンコードされ、そのファイルに対する新しい名前の構築に使用されることに注意してください。この名前は、デフォルトの"download"アクションによって取り出され、元のファイルへのContent-Dispositionヘッダを設定するのに使用されます。

Notice that, by default, the original filename of an uploaded file is b16encoded and used to build the new name for the file. This name is retrieved by the default "download" action and used to set the content disposition header to the original filename.

拡張子だけがそのままになります。これはセキュリティ上の理由です。なぜなら、ファイル名は特別な文字列を含む可能性があり、訪問者にディレクトリ・トラバーサル攻撃や他の悪意のある操作を許してしまうからです。

Only its extension is preserved. This is a security requirement since the filename may contain special characters that could allow a visitor to perform directory traversal attacks or other malicious operations.

新しいファイル名はform.vars.imageにも格納されます。

The new filename is also stored in form.vars.image.

UPDATEフォームを使用してレコードを編集するとき、既存のアップロードしたファイルへのリンクを表示するのはいいことで、web2pyはその方法を提供しています。

When editing the record using an UPDATE form, it would be nice to display a link to the existing uploaded file, and web2py provides a way to do it.

URLをupload引数を介してSQLFORMのコンストラクタに渡す場合、web2pyは、ファイルをダウンロードするために、そのURLのアクションを用います。次のアクションを考えてください:

If you pass a URL to the SQLFORM constructor via the upload argument, web2py uses the action at that URL to download the file. Consider the following actions:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

def display_form():

record = db.person(request.args(0)) or redirect(URL('index'))

form = SQLFORM(db.person, record, deletable=True,

upload=URL('download'))

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

response.flash = 'form accepted'

elif form.errors:

response.flash = 'form has errors'

return dict(form=form)

def download():

return response.download(request, db)

さて、次のURLにて新規のレコードを挿入してみます:

Now, insert a new record at the URL:

http://127.0.0.1:8000/test/default/display_form

画像をアップロードして、フォームをサブミットして、次のURLを訪れて新しく作られたレコードを編集します:

Upload an image, submit the form, and then edit the newly created record by visiting:

http://127.0.0.1:8000/test/default/display_form/3

(ここでは最新のレコードがid=3をもつと仮定します)。フォームは以下に示すように画像のプレビューを表示します:

(here we assume the latest record has id=3). The form will display an image preview as shown below:

このフォームは、シリアライズされるときに、次のようなHTMLを生成します:

This form, when serialized, generates the following HTML:

1.

2.

3.

4.

5.

6.

7.

<td><label id="person_image__label" for="person_image">Image: </label></td>

<td><div><input type="file" id="person_image" class="upload" name="image"

/>[<a href="/test/default/download/person.image.0246683463831.jpg">file</a>|

<input type="checkbox" name="image__delete" />delete]</div></td><td></td></tr>

<tr id="delete_record__row"><td><label id="delete_record__label" for="delete_record"

>Check to delete:</label></td><td><input type="checkbox" id="delete_record"

class="delete" name="delete_this_record" /></td>

これは、アップロードしたファイルをダウンロードできるようにするリンクと、データベースのレコードからこのファイルを削除するためのチェックボックスを含んでいます。したがって、"image"フィールドにはNULLが格納されています。

which contains a link to allow downloading of the uploaded file, and a checkbox to remove the file from the database record, thus storing NULL in the "image" field.

なぜ、このような機構が公開されているのでしょうか?なぜ、ダウンロード関数を書く必要があるのでしょうか?なぜなら、いくつかの認証メカニズムをダウンロード関数に課すことが必要になるかもしれないからです。例は、第8章を参照してください。

Why is this mechanism exposed? Why do you need to write the download function? Because you may want to enforce some authorization mechanism in the download function. See Chapter 8 for an example.

元のファイル名の保存

Storing the Original Filename

web2pyは自動的に元のファイル名を新しいUUIDのファイル名の中に保存し、ファイルがダウンロードされたときにそれを取り出します。ダウンロードの際、オリジナルのファイル名は、HTTPレスポンスの Content-Dispositionヘッダに格納されます。これはすべて、プログラミングの必要なしに透過的に行われます。

web2py automatically stores the original filename inside the new UUID filename and retrieves it when the file is downloaded. Upon download, the original filename is stored in the content-disposition header of the HTTP response. This is all done transparently without the need for programming.

時には、オリジナルのファイル名をデータベースのフィールドに保存したい場合もあります。この場合、モデルを修正し、それを保存するフィールドを加える必要があります:

Occasionally you may want to store the original filename in a database field. In this case, you need to modify the model and add a field to store it in:

1.

2.

3.

4.

db.define_table('person',

Field('name', requires=IS_NOT_EMPTY()),

Field('image_filename'),

Field('image', 'upload'))

このとき、それを処理するようにコントローラーを次のように修正する必要があります:

then you need to modify the controller to handle it:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

def display_form():

record = db.person(request.args(0)) or redirect(URL('index'))

url = URL('download')

form = SQLFORM(db.person, record, deletable=True,

upload=url, fields=['name', 'image'])

if request.vars.image!=None:

form.vars.image_filename = request.vars.image.filename

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

response.flash = 'form accepted'

elif form.errors:

response.flash = 'form has errors'

return dict(form=form)

SQLFORMは"image_filename"フィールドを表示していないことに注意してください。"display_form"アクションは、request.vars.imageのファイル名をform.vars.image_filenameに移動します。これにより、acceptsにおいてそれを処理し、データベースに保存することができるようになります。ダウンロード関数は、そのファイルを配信する前に、元のファイル名をデータベースにおいてチェックし、Content-Dispositionヘッダにおいて使用します。

Notice that the SQLFORM does not display the "image_filename" field. The "display_form" action moves the filename of the request.vars.image into the form.vars.image_filename, so that it gets processed by accepts and stored in the database. The download function, before serving the file, checks in the database for the original filename and uses it in the content-disposition header.

autodelete

レコードを削除する際に、SQLFORMはレコードによって参照された物理的なアップロード・ファイルを削除することはありません。その理由は、web2pyがそのファイルが他のテーブルによって使用/リンクされているか、また、他の目的でしようされているかどうか知ることができないからです。対応するレコードが削除されたとき、実際のファイルを削除しても安全だと判断できる場合は、次のようにしてそうすることができます:

The SQLFORM, upon deleting a record, does not delete the physical uploaded file(s) referenced by the record. The reason is that web2py does not know whether the same file is used/linked by other tables or used for other purpose. If you know it is safe to delete the actual file when the corresponding record is deleted, you can do the following:

1.

2.

3.

db.define_table('image',

Field('name', requires=IS_NOT_EMPTY()),

Field('file','upload',autodelete=True))

autodelete属性はデフォルトではFalseです。Trueに設定すると、レコードが削除されるとき、ファイルも削除されるようになります。

The autodelete attribute is False by default. When set to True is makes sure the file is deleted when the record is deleted.

参照レコードへのリンク

Links to Referencing Records

今度は、参照フィールドによってリンクされた2つのテーブルを考えます。

Now consider the case of two tables linked by a reference field. For example:

1.

2.

3.

4.

5.

6.

db.define_table('person',

Field('name', requires=IS_NOT_EMPTY()))

db.define_table('dog',

Field('owner', db.person),

Field('name', requires=IS_NOT_EMPTY()))

db.dog.owner.requires = IS_IN_DB(db,db.person.id,'%(name)s')

personはdogsを持ち、各dogは所有者(owner)、つまり、personに所属しています。dogの所有者(owner)には、有効なdb.person.idを'%(name)s'を用いて参照することが要求されます。

A person has dogs, and each dog belongs to an owner, which is a person. The dog owner is required to reference a valid db.person.id by '%(name)s'.

このアプリケーションのappdadminインターフェースを用いて、何人かのpersonと彼らのdogsを加えましょう。

Let's use the appadmin interface for this application to add a few persons and their dogs.

既存のpersonを編集するとき、appadminのUPDATEフォームは、このpersonに属するdogsの一覧を表示するページへのリンクを表示します。この挙動は、SQLFORMのlinkto引数を用いて真似することができます。linktoは、SQLFORMからのクエリ文字列を受け取って対応するレコードを返す新規のアクションのURLを指す必要があります。以下がその例です。

When editing an existing person, the appadmin UPDATE form shows a link to a page that lists the dogs that belong to the person. This behavior can be replicated using the linktoargument of the SQLFORM. linkto has to point to the URL of a new action that receives a query string from the SQLFORM and lists the corresponding records. Here is an example:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

def display_form():

record = db.person(request.args(0)) or redirect(URL('index'))

url = URL('download')

link = URL('list_records')

form = SQLFORM(db.person, record, deletable=True,

upload=url, linkto=link)

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

response.flash = 'form accepted'

elif form.errors:

response.flash = 'form has errors'

return dict(form=form)

これがそのページです:

Here is the page:

"dog.owner"というリンクがあります。このリンクの名前は、次のようなSQLFORMのlabels引数を介して変更することができます:

There is a link called "dog.owner". The name of this link can be changed via the labelsargument of the SQLFORM, for example:

1.

labels = {'dog.owner':"This person's dogs"}

リンクをクリックすると、次の場所に向かいます:

If you click on the link you get directed to:

1.

/test/default/list_records/dog?query=dog.owner%3D5

"list_records"は指定されたアクションで、request.args(0)に参照するテーブルの名前が設定され、request.vars.queryにSQLのクエリ文字列が設定されています。URLのクエリ文字列は適切にurlエンコードされた"dog.owner=5"の値を含んでいます(web2pyはURLを解析するときに自動的にこれをデコードします)。

"list_records" is the specified action, with request.args(0) set to the name of the referencing table and request.vars.query set to the SQL query string. The query string in the URL contains the value "dog.owner=5" appropriately url-encoded (web2py decodes this automatically when the URL is parsed).

とても汎用的な"list_records"アクションを次のように簡単に実装することができます:

You can easily implement a very general "list_records" action as follows:

1.

2.

3.

4.

5.

def list_records():

table = request.args(0)

query = request.vars.query

records = db(query).select(db[table].ALL)

return dict(records=records)

関連付けられるビュー"default/list_records.html"は次のようにします:

with the associated "default/list_records.html" view:

1.

2.

{{extend 'layout.html'}}

{{=records}}

選択によってレコードセットが返され、ビューでシリアライズされるとき、これは最初にSQLTABLEオブジェクト(Tableと同じではありません)に変換された後、各フィールドがテーブルのカラムと対応するHTMLテーブルへとシリアライズされます。

When a set of records is returned by a select and serialized in a view, it is first converted into a SQLTABLE object (not the same as a Table) and then serialized into an HTML table, where each field corresponds to a table column.

フォームの事前入力

Pre-populating the form

次の構文を用いて、フォームを事前入力することは常に可能です:

It is always possible to pre-populate a form using the syntax:

1.

form.vars.name = 'fieldvalue'

上記のような文は、フィールド(この例では"name")が明示的にフォームで表示されるかにかかわらず、フォームの宣言の後、かつ、フォームの受理の前に挿入される必要があります。

Statements like the one above must be inserted after the form declaration and before the form is accepted, whether or not the field ("name" in the example) is explicitly visualized in the form.

SQLFORMへのさらなるフォーム要素の追加

Adding extra form elements to SQLFORM

時として、フォームを作成した後、フォームにさらなる要素を加えたい場合があります。たとえば、ユーザーに対してWebサイトの契約条件への承認を確認するチェックボックスを加えたい場合があります:

Sometimes you may wish to add an extra element to your form after it has been created. For example, you may wish to add a checkbox which confirms the user agrees with the terms and conditions of your website:

1.

2.

3.

4.

form = SQLFORM(db.yourtable)

my_extra_element = TR(LABEL('I agree to the terms and conditions') \

,INPUT(_name='agree',value=True,_type='checkbox'))

form[0].insert(-1,my_extra_element)

変数my_extra_elementは、formstyleに適合しておく必要があります。個の例では、デフォルトのformstyle='table3cols'が想定されています。

The variable my_extra_element should be adapted to the formstyle. In this example, the default formstyle='table3cols' has been assumed.

サブミット後に、form.vars.agreeはチェックボックスのステータスを保持します。そのステータスはたとえばonvalidation関数において使用されます。

After submission, form.vars.agree will contain the status of the checkbox, which could then be used in an onvalidation function, for instance.

データベースIOなしのSQLFORM

SQLFORM without database IO

SQLFORMを使用してデータベーステーブルからフォームを生成し、サブミットしたフォームをそのまま検証するが、データベースにおいて自動的なINSERT/UPDATE/DELTEを行いたくない場合があります。たとえば、1つのフィールドが他の入力フィールドから計算される必要がある場合です。また、挿入されたデータに対して標準の検証では達成できない追加の検証を行いたい場合です。

There are times when you want to generate a form from a database table using SQLFORM and you want to validate a submitted form accordingly, but you do not want any automatic INSERT/UPDATE/DELETE in the database. This is the case, for example, when one of the fields needs to be computed from the value of other input fields. This is also the case when you need to perform additional validation on the inserted data that cannot be achieved via standard validators.

これは、次のものを:

This can be done easily by breaking:

1.

2.

3.

form = SQLFORM(db.person)

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

response.flash = 'record inserted'

以下のように分解して簡単に行うことができます。

into:

1.

2.

3.

4.

5.

form = SQLFORM(db.person)

if form.accepts(request.vars, session, dbio=False):

### deal with uploads explicitly

form.vars.id = db.person.insert(**dict(form.vars))

response.flash = 'record inserted'

同じことはUPDATE/DELETEフォームでも行うことができます。次のものを:

The same can be done for UPDATE/DELETE forms by breaking:

1.

2.

3.

form = SQLFORM(db.person,record)

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

response.flash = 'record updated'

以下のように分解します。

into:

1.

2.

3.

4.

5.

6.

7.

form = SQLFORM(db.person,record)

if form.accepts(request.vars, session, dbio=False):

if form.vars.get('delete_this_record', False):

db(db.person.id==record.id).delete()

else:

record.update_record(**dict(form.vars))

response.flash = 'record updated'

両者の場合でも、web2pyはアップロードファイルの保存とリネームを、dbio=Trueのように、つまりデフォルトのシナリオのように、処理します。アップロードされたファイル名は以下にあります:

In both cases web2py deals with the storage and renaming of the uploaded file as if dbio=True, the default scenario. The uploaded filename is in:

1.

form.vars.fieldname