2007年11月9日

FormBuildとToscaWidgets

Pylonsでのフォーム



Djangoにはformやnewformとかあるらしいし、TurboGearsには、Widgetがある。
PylonsはWebHelperというRailsから(ryモジュールを使って、urlを生成したり、フォームを作ったりする。



ただ、WebHelperでフォームを作ると、値の保持やら、エラーメッセージを出したりなんだりと自分でやらないといけない。
BuildFormは、この辺を助けてくれるモジュールだ。
入力チェック自体は、FormEncodeを使うようになっている。
ToscaWidgetsは、さらに一歩進んで、フォームなどを再利用可能な部品にして使えるようになっている。
どちらも、フォームをプログラマブルに制御するという共通点はあるものの、アプローチは大きく異なる。



BuildFormは主に、テンプレート内で、フォームを作るために使われる。
一方ToscaWidgetは、フォームそのものをオブジェクトとして作成する。
テンプレート内ではオブジェクトが自分をHTMLで表現するだけだ。


BuildForm



細かい準備があるけど、その辺はBuildFormのドキュメントにゆずるとして、コントローラーとテンプレート内での具体例。



まずは、コントローラー内。

def edit(self, id, format='html'):
"""GET /pages/id;edit: Form to edit an existing item."""
# url_for('edit_page', id=ID)
page = model.Page.query.get(id)
c.page = page
c.form = model.forms.build.StandardForm(defaults=dict(pagename=page.pagename,
contents=page.contents))
return render('/pages/form.mako')




そして、テンプレート内。
フォームの具体的なレイアウトはここで決まる。

${c.form.start(action=h.url_for('page', id=c.page.id), method='post')}
${c.form.field.hidden('_method', value='put')}
${c.form.layout.simple_start()}
${c.form.layout.entry(
c.form.field.text('pagename'),
name='Pagename',
error=c.form.get_error('pagename')
)}
${c.form.layout.entry(
c.form.field.text_area('contents', size='80x20'),
name='Contents',
error=c.form.get_error('contens')
)}
${c.form.layout.simple_end()}
${c.form.field.submit(value='Save')}
${c.form.end()}



ToscaWidgets



続いて、ToscaWidgetsの例。



昔試したコードが通らなくなっていた。
ミドルウェアの扱いが変わったようで、ToscaWidgets-0.1a2dev_r3402の時点では、middleware.pyの中で、以下のように設定する。

from toscawidgets.middleware import TGWidgetsMiddleware
from toscawidgets.mods.pylonshf import PylonsHostFramework
host_framework = PylonsHostFramework(default_view="mako")
app = TGWidgetsMiddleware(app, host_framework)

しかし、本当にドキュメントが少ない。
っていうか、ToscaWidgetsのドキュメントよりもPylonsのドキュメントを見た方がいい。



では、フォームクラスの定義。

from toscawidgets.api import WidgetsList
from toscawidgets.widgets import forms
from toscawidgets.widgets.forms import validators

class PageForm(forms.TableForm):
class fields(WidgetsList):
pagename = forms.TextField(validator=validators.UnicodeString(not_empty=True))
contents = forms.TextArea(validator=validators.UnicodeString(not_empty=True))


フォームレイアウトはこの時点で決まる。
また、フォームそのものが、入力チェック内容を持ち、FormEncodeのSchemaの役目を果たす。



続いて、コントローラー。
BuildFormと比べて、それほど変わりはない。

from toscawidgets.mods.pylonshf import render_response, validate

...

def edit(self, id, format='html'):
"""GET /pages/id;edit: Form to edit an existing item."""
# url_for('edit_page', id=ID)
page = model.Page.query.get(id)
c.page = page
c.form = model.forms.PageForm()
return render_response('/pages/form.mako')


ここで、render_responseを使っているが、これは、pylonsのrender_responseではなく、ToscaWidgetが用意しているrender_responseだ。



そして、テンプレート内。
レイアウトは既に定義済みなので、BuildFormと比べて簡潔だ。


${c.form(c.page, action=h.url_for('page', id=c.page.id))}


ただ、テンプレートを見ただけでは、どんなHTMLになるか分からない。




ToscaWidgetsは、既に実績あるTurboGearsのWidgetが独立したものだが、ドキュメントが少なく、全貌が分かりにくい。
あと、バージョンが0.1a2あたりから一向に進まないのが気になる。
かなり重厚なモジュールだし、完成するのも、使いこなすにも、時間がかかりそうだ。
モジュール自体のパワフルさは断然TosaWidgetだと思うのだが、現時点で使うとしたらBuildFormの方が良さそうだ。



参考