JavascriptやCSSの取り込み

さて、ToscaWidgetでフォームを表示できたわけだが、CalendarなどJavascriptを使うウィジェットが動かなかった。
さらに追加でやることがある。
toscawidgets.api.retrieve_resources を使って、そのウィジェットに必要なJSやCSSを取得して、テンプレート側に展開しないといけない。
このあたりドキュメントがなく、サンプルコードだけが頼りだ。

以下は、resourcesの処理を、昨日のコードに追加したものだ。

    def index(self):
        c.values = dict(name=u'aodag', introduction=u'Pythonプログラマー')
        c.form = UserForm()
        resources = retrieve_resources(c.form)
        return render_response("/main_index.html", resources=resources)

render_responseのキーワード引数でresourcesを渡す。
一回c.resourcesで試してみたが、うまく渡っていなかった。
コードを参照してみると、中でc.resourcesに値を設定しているので上書きされて消えてしまうようだ。
c.w にウィジェットを渡しておけば、retrive_resourceなど必要な処理をやってくれるようなので、書き換えた。

    def index(self):
        c.values = dict(name=u'aodag', introduction=u'Pythonプログラマー')
        c.form = UserForm()
        c.w = [c.form]
        return render_response("/main_index.html")

上記どちらのコードでも、テンプレート内では、c.resourcesに必要なものが入っている。

次は、これらのリソース(JSLinkやCSSLinkなど)をテンプレート内で展開しないといけない。
展開するポイントは、head内, bodyの最初, bodyの最後。

# -*- coding:utf-8 -*-
<?xml version="1.0"?>
<html>
  <head>
    %for rsc in c.resources.get('head', []):
    ${rsc.display()}
    %endfor
  </head>
  <body>
    %for rsc in c.resources.get('bodytop', []):
    ${rsc.display()}
    %endfor
    ${c.resources}
    ${c.form.display(c.values, action='save')}
    %for rsc in c.resources.get('bodybottom', []):
    ${rsc.display()}
    %endfor
  </body>
</html>

c.resource内にそれぞれ、head, bodytop, bodybottom にわけられているので、それらを展開して表示させる。
やることが多いので、このあたりはベーステンプレートにまとめておいたほうが良さそうだ。

Pylons上のMakoでToscaWidgets使ってみる

もうなんだか組み合わせがえらいことになってきている。
ToscaWidgetsのtwformsはテンプレートエンジンにGenshi使ってるし。

まずはwsgiミドルウェアを設定する。
config/middleware.py

...

from toscawidgets.middleware import make_middleware
...


def make_app(global_conf, full_stack=True, **app_conf):
    ...

    app = make_middleware(app, global_conf, host_framework="pylons")

フォームを作る。

class UserFormFields(WidgetsList):
    name = forms.TextField("name")
    introduction = forms.TextArea("intoduction")

class UserForm(forms.TableForm):
    fields = UserFormFields()

コントローラー内では、テンプレート参照用にcへformを設定する。
(ん?formはグローバルに作った方が良いのだっただろうか?)
また、ToscaWidgets提供のrender_responseで、Responseを作成する。

from toscawidgets.mods.pylonshf import validate, render_response

class MainController(BaseController):

    def index(self):
        c.values = dict(name=u'aodag', introduction=u'Pythonプログラマー')
        c.form = UserForm()
        return render_response("/main_index.html")

テンプレートの中では、formにvaluesを渡して呼び出す。
0.9.6からはデフォルトでMakoが使われるようだ。

# -*- coding:utf-8 -*-
<?xml version="1.0"?>
<html>
  <body>
    ${c.form(c.values)}
  </body>
</html>

1行目の文字コード設定はPythonコード内に書くのと同じ。
書かないとマルチバイト文字でおこられるよ。

FormBuild

Pylonsのスポンサー?なのかな3aimsのモジュール
http://formbuild.org/
formencodeと連携して、フォーム作成を支援するもの。
PylonsではWebHelperが同様のポジションにあるけど、今後はこっちになるのだろうか?

TG系ではもともとWidgetがあって、ToscaWidgetsに分離している。
ToscaWidgetsのほうがコンポーネントっぽく、再利用性を重視しているのに対して、formbuildはあくまでもフォーム生成を支援することに注力しているようだ。
生成するときの書き方はいかにもプログラムな書き方になる。
フォームレイアウトは、交換可能になっていて、自分で拡張したレイアウトを使うことができる。