VariousWeb Form Widget Toolkits          aodag     Pycon JP 2011
お前誰よ@aodag小田切篤BeProud勤務今別の部屋で発表しているianと同僚Djangoきらいです(´・ω・`) PylonsとかPyramidとか、既存のコンポーネント組み合わせてるもののほうが好きです。
SQLAlchemy● データマッパー● すごく柔軟
WSGI (PEP-333, PEP-3333)PythonのWebアプリケーション標準def hello(environ, start_response):  start_response("200 OK",     [(Content-ty...
AdminアプリケーションDjangoのadmin(だけ)はいいね!SQLAlchemyにも同じようなものがほしいWSGIアプリで全般的に使いたい(あまりフレームワークに依存したくない)Ajaxばりばりである必要はないけど、DatePicker...
Adminアプリケーション● クラスごとにサブアプリケーション● グリッド表示と検索● 入力フォーム● カスタムアクションを追加できる
フォームライブラリを調査Form Libraryの役割比較ライブラリ
Form Libraryの役割● HTMLフォーム生成● バリデーション
比較ライブラリ● ToscaWidgets / Sprox● FormAlchemy● tw2.sqla● WTForms● deform/colander
比較のポイント● SQLAlchemyとの親和性● バリデータのカスタマイズ● フィールドのカスタマイズ● ウィジェットのカスタマイズ
ToscaWidgets / Sprox● SproxはSQLAlchemyのスキーマからToscaWidgetsのフォームを  作成します● SQLAlchemyのスキーマ以外のフィールドをフォームに追加した  り、スキーマのフィールドをフォ...
FormAlchemy● SQLAlchemyだけでなく、zope.schemaなどにも対応● SQLAlchemyのスキーマ対応は一番すぐれている● デフォルトで用意されているウィジェットレンダラーが少ない● 実行時にもフィールド定義を変更可...
tw2● ToscaWidgetsの後継● まだ a4がリリースされたばかり、 発展途上● SQLAlchemyから自動生成するフォームがある   ○ many-to-manyまでは対応できてない● SQLAlchemyというよりElixirに...
wtforms● SQLAlchemyからのスキーマ生成はしない● SelectのoptionをSQLAlchemyのクエリで設定可能● 機能は少なめ● その分はまりどころが少なく枯れるのが早そう● フォーム全体の生成はしない● グリッド生成も...
deform / colander ● colanderはスキーマ定義 ● deformはcolanderに対応しているフォームライブラリ ● SQLAlchemyからのスキーマ生成できない ● ウィジェットが豊富 ● ajaxとりこみに意欲的...
Sample ModelSQLAlchemy ● User    ○ user_name    ○ password    ○ user_image    ○ groups ● Group    ○ name    ○ users    ○ p...
ポイント● 全部many-to-manyの関連付け● User - Group - Permission● User - Permissionの派生関連付け● _password 直接見せたくないフィールド● ユーザー画像はファイル保存
Userフォーム Sproxclass UserForm(AddRecordForm):   __model__ = models.User   __require_fields__ = [user_name]   __omit_fields_...
Userグリッド Sproxclass UserTable(TableBase):   __model__ = models.Useruser_table = UserTable(models.DBSession)class UserTable...
Sprox雑感● AddRecordFormとEditableFormをそれぞれ作らないといけない● SQLAlchemy0.7で動かない!● many-to-manyがうまくフォームに反映されない● デフォルトでアルファベット順になってしまう...
(´・ω・`) そろそろオワコン?
Userフォーム FormAlchemyclass UserForm(FieldSet):   def __init__(self, **kw):     super(UserForm, self).__init__(model=User, *...
User グリッド FormAlchemyclass UserGrid(Grid):   def __init__(self, **kw):     super(UserGrid, self).__init__(cls=models.User,...
FormAlchemy雑感やっぱりSQLAlchemy0.7で動かない(´・ω・`) fa.jqueryはまだ安定していないmany-to-manyをしっかりおいかけてくれる開発が活発なので、今後に期待できる
全体的には(・∀・)イイ!  と思う
Userフォーム tw2.sqlaclass UserForm(tw2.sqla.DbFormPage):   entity = models.User   class child(tw2.forms.TableForm):      user...
● SQLAlchemyのスキーマから自動生成する機能が追加されてき  ていますが、使い物になりませんでした。(´・ω・`) ● あと、entityクラスのqueryメソッドを呼ぼうとしたり、Elixirを前提に  しすぎです。● 遅延評価でき...
(゚д゚)マダマダ
Userフォーム WTFormsdef group_factory():  return models.DBSession.query(models.Group)class UserForm(wtforms.Form):   username ...
WTForms表示<form method="post"><table>${self.field_row(form.username)}${self.field_row(form.password)}${self.field_row(form....
WTForms 表示<%def name="field_row(field)"><tr><td>${field.label}</td><td>${field()}</td></tr></%def>
WTForms 雑感● やれることが少ない分、はまりどころはなさそうです● でもフォームライブラリ使ってるのにHTMLテーブル書くのはやで  す。● B2Cサイトで複雑なHTMLに入れるのに向いてそうですが、そん  なことは他のフォームライブラ...
機能少なすぎね? (´・ω・`) 
Userフォーム deformclass UserSchema(c.MappingSchema):   # colanderはSQLAlchemyから自動生成しない   user_name = c.SchemaNode(c.String()) ...
colanderのdeferred bind 定義実行時に、ウィジェット、やバリデータを切り替える仕組み@c.deferreddef group_select_widget(node, kw):  groups = kw[groups]  re...
colander deffered bindingclass Group(c.MappingSchema):   # groupを選択するためのスキーマ   group_id = c.SchemaNode(c.String(),        ...
colanderのdeferred bind バインディングschema = UserSchema()groups = DBSession.query(Group)# バインドschema = schema.bind(groups=groups...
User フォーム deform バリデーションtry:   params = form.validate(controls)except ValidationFailure, e:   e.render()
deform 雑感● フォームでやりたいことは、おそらくなんでもできます。● シーケンススキーマやマッピングスキーマを組み合わせることで、  複雑な階層を持つスキーマも作成可能。● その分ライブラリの構造が複雑です。
(´  > ω < )  むずかしー!
ひとまずSQLAlchemyのデータ管理ツールを作るなら、FormAlchemyが一番サポートされている。fa.jqueryは様子見たほうがいい。1リクエストで複数のモデルを扱う場合は、colander / deform がほぼどんな構造でも対...
スタティックファイルの管理deformやfa.jqueryはjquery.jsやjqueryui.js、その他cssなどが必要フロントのApacheやnginexに任せてしまいたいが、フォームライブラリが使うスタティックファイルはどこにあるのか...
Paste deployでがんばr[app:deform_static]use = egg:paste#pkg_resourcesegg = deformresource_name = deform/static[composite:defor...
Fanstatic ● スタティックファイルをホスティングするWSGIアプリ ● スタティックファイルを管理するユーティリティ、ミドルウェア ● fa.jqueryは今後これを使うようになる予定http://pypi.python.org/py...
Fanstatic 例from fanstatic import Fanstaticfrom js.jqueryui import jqueryui@wsgifydef app(request):  jqueryui.need()  retur...
Fanstatic 例body = """<html><head></head><body>Hello</body></html>"""
Fanstatic 例 実行結果<html><head>  <script type="text/javascript" src="/fanstatic/jquery/jquery.js"></script><script type="text...
参考● SQLAlchemy http://www.sqlalchemy.org/● ToscaWidgets http://toscawidgets.org/● formencode http://formencode.org/● Sprox...
Form libraries
Form libraries
Form libraries
Form libraries
Form libraries
Form libraries
Form libraries
Form libraries
Upcoming SlideShare
Loading in …5
×

Form libraries

2,017 views

Published on

Pycon JP 2011 8/27

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,017
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
3
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Form libraries

  1. 1. VariousWeb Form Widget Toolkits aodag Pycon JP 2011
  2. 2. お前誰よ@aodag小田切篤BeProud勤務今別の部屋で発表しているianと同僚Djangoきらいです(´・ω・`) PylonsとかPyramidとか、既存のコンポーネント組み合わせてるもののほうが好きです。
  3. 3. SQLAlchemy● データマッパー● すごく柔軟
  4. 4. WSGI (PEP-333, PEP-3333)PythonのWebアプリケーション標準def hello(environ, start_response): start_response("200 OK", [(Content-type, text/plain)]) return ["Hello, world!"]
  5. 5. AdminアプリケーションDjangoのadmin(だけ)はいいね!SQLAlchemyにも同じようなものがほしいWSGIアプリで全般的に使いたい(あまりフレームワークに依存したくない)Ajaxばりばりである必要はないけど、DatePickerとかSuggestとか、入力補助系のJSが利用できるとよい
  6. 6. Adminアプリケーション● クラスごとにサブアプリケーション● グリッド表示と検索● 入力フォーム● カスタムアクションを追加できる
  7. 7. フォームライブラリを調査Form Libraryの役割比較ライブラリ
  8. 8. Form Libraryの役割● HTMLフォーム生成● バリデーション
  9. 9. 比較ライブラリ● ToscaWidgets / Sprox● FormAlchemy● tw2.sqla● WTForms● deform/colander
  10. 10. 比較のポイント● SQLAlchemyとの親和性● バリデータのカスタマイズ● フィールドのカスタマイズ● ウィジェットのカスタマイズ
  11. 11. ToscaWidgets / Sprox● SproxはSQLAlchemyのスキーマからToscaWidgetsのフォームを 作成します● SQLAlchemyのスキーマ以外のフィールドをフォームに追加した り、スキーマのフィールドをフォームから削除したりできます。● formencodeでカスタムバリデータを作成します● tw.formsでカスタムフィールドを作成します
  12. 12. FormAlchemy● SQLAlchemyだけでなく、zope.schemaなどにも対応● SQLAlchemyのスキーマ対応は一番すぐれている● デフォルトで用意されているウィジェットレンダラーが少ない● 実行時にもフィールド定義を変更可能● jqueryuiを使ったfa.jqueryのような追加スキンが存在する
  13. 13. tw2● ToscaWidgetsの後継● まだ a4がリリースされたばかり、 発展途上● SQLAlchemyから自動生成するフォームがある ○ many-to-manyまでは対応できてない● SQLAlchemyというよりElixirに対応している
  14. 14. wtforms● SQLAlchemyからのスキーマ生成はしない● SelectのoptionをSQLAlchemyのクエリで設定可能● 機能は少なめ● その分はまりどころが少なく枯れるのが早そう● フォーム全体の生成はしない● グリッド生成もしない● ToscaWidgetsのtw.formsと名前が紛らわしい><
  15. 15. deform / colander ● colanderはスキーマ定義 ● deformはcolanderに対応しているフォームライブラリ ● SQLAlchemyからのスキーマ生成できない ● ウィジェットが豊富 ● ajaxとりこみに意欲的 ● deferred bindingにより実行時にウィジェットやバリデーションを変 更可能 ● テンプレートにchameleon(zope page template)を使っている ● テンプレートをmakoに入れ替えるプロジェクトが進行中http://deformdemo.repoze.org/
  16. 16. Sample ModelSQLAlchemy ● User ○ user_name ○ password ○ user_image ○ groups ● Group ○ name ○ users ○ permissions ● Permission ○ name ○ groups
  17. 17. ポイント● 全部many-to-manyの関連付け● User - Group - Permission● User - Permissionの派生関連付け● _password 直接見せたくないフィールド● ユーザー画像はファイル保存
  18. 18. Userフォーム Sproxclass UserForm(AddRecordForm): __model__ = models.User __require_fields__ = [user_name] __omit_fields__ = [_password] __field_order__ = [user_name, password, groups] password = tw.forms.PasswordField(password, validator=tw.forms.validators.NotEmpty)
  19. 19. Userグリッド Sproxclass UserTable(TableBase): __model__ = models.Useruser_table = UserTable(models.DBSession)class UserTableFiller(TableFiller): __model__ = models.Useruser_table_filler = UserTableFiller(models.DBSession)user_table(user_table_filler.get_value())
  20. 20. Sprox雑感● AddRecordFormとEditableFormをそれぞれ作らないといけない● SQLAlchemy0.7で動かない!● many-to-manyがうまくフォームに反映されない● デフォルトでアルファベット順になってしまうので、いい感じの順 番にするには、全部指定しなおさないといけません(´・ω・`) 
  21. 21. (´・ω・`) そろそろオワコン?
  22. 22. Userフォーム FormAlchemyclass UserForm(FieldSet): def __init__(self, **kw): super(UserForm, self).__init__(model=User, **kw) excludes = [self._password] # 追加フィールド self.insert_after(self.user_name, Field(password).password().required()) self.configure(exclude=excludes) # フォーム全体の設定
  23. 23. User グリッド FormAlchemyclass UserGrid(Grid): def __init__(self, **kw): super(UserGrid, self).__init__(cls=models.User, **kw) # Edit用のリンク追加 self.append(Field(edit_link, value=lambda u: <a href="%s/edit">Edit</a> % u.id)) self.configure(readonly=True, exclude=[self._password])users = models.DBSession.query(models.User).all()grid = user_grid.bind(users)
  24. 24. FormAlchemy雑感やっぱりSQLAlchemy0.7で動かない(´・ω・`) fa.jqueryはまだ安定していないmany-to-manyをしっかりおいかけてくれる開発が活発なので、今後に期待できる
  25. 25. 全体的には(・∀・)イイ! と思う
  26. 26. Userフォーム tw2.sqlaclass UserForm(tw2.sqla.DbFormPage): entity = models.User class child(tw2.forms.TableForm): user_name = tw2.forms.TextField(validator=tw2.core.Required) password = tw2.forms.PasswordField(validator=tw2.core.Required) user_image = tw2.forms.FileField() groups = tw2.sqla.DbSingleSelectField(entity=models.Group)
  27. 27. ● SQLAlchemyのスキーマから自動生成する機能が追加されてき ていますが、使い物になりませんでした。(´・ω・`) ● あと、entityクラスのqueryメソッドを呼ぼうとしたり、Elixirを前提に しすぎです。● 遅延評価できるselectウィジェットに複数選択可能なものがなく、 many-to-manyの関連付けに困ります
  28. 28. (゚д゚)マダマダ
  29. 29. Userフォーム WTFormsdef group_factory(): return models.DBSession.query(models.Group)class UserForm(wtforms.Form): username = wtforms.TextField(User Name) password = wtforms.PasswordField(Password) groups = QuerySelectMultipleField(query_factory=group_factory )
  30. 30. WTForms表示<form method="post"><table>${self.field_row(form.username)}${self.field_row(form.password)}${self.field_row(form.groups)}</table><button type="submit">Add</button></form>
  31. 31. WTForms 表示<%def name="field_row(field)"><tr><td>${field.label}</td><td>${field()}</td></tr></%def>
  32. 32. WTForms 雑感● やれることが少ない分、はまりどころはなさそうです● でもフォームライブラリ使ってるのにHTMLテーブル書くのはやで す。● B2Cサイトで複雑なHTMLに入れるのに向いてそうですが、そん なことは他のフォームライブラリでできます
  33. 33. 機能少なすぎね? (´・ω・`) 
  34. 34. Userフォーム deformclass UserSchema(c.MappingSchema): # colanderはSQLAlchemyから自動生成しない user_name = c.SchemaNode(c.String()) password = c.SchemaNode(c.String(), widget=w.PasswordWidget())form = Form(UserSchema(), buttons=(save,))
  35. 35. colanderのdeferred bind 定義実行時に、ウィジェット、やバリデータを切り替える仕組み@c.deferreddef group_select_widget(node, kw): groups = kw[groups] return w.SelectWidget(values=[ (g.id, g.group_name) for g in groups ])
  36. 36. colander deffered bindingclass Group(c.MappingSchema): # groupを選択するためのスキーマ group_id = c.SchemaNode(c.String(), widget=group_select_widget)class Groups(c.SequenceSchema): # groupを複数選択するためのスキーマ group = Group()class UserSchema(c.MappingSchema): ...... groups = Groups()
  37. 37. colanderのdeferred bind バインディングschema = UserSchema()groups = DBSession.query(Group)# バインドschema = schema.bind(groups=groups)form = Form(schema, ....)
  38. 38. User フォーム deform バリデーションtry: params = form.validate(controls)except ValidationFailure, e: e.render()
  39. 39. deform 雑感● フォームでやりたいことは、おそらくなんでもできます。● シーケンススキーマやマッピングスキーマを組み合わせることで、 複雑な階層を持つスキーマも作成可能。● その分ライブラリの構造が複雑です。
  40. 40. (´  > ω < ) むずかしー!
  41. 41. ひとまずSQLAlchemyのデータ管理ツールを作るなら、FormAlchemyが一番サポートされている。fa.jqueryは様子見たほうがいい。1リクエストで複数のモデルを扱う場合は、colander / deform がほぼどんな構造でも対応できる。MongoDBなどスキーマレスDBを使う場合は、こちらをおすすめする。
  42. 42. スタティックファイルの管理deformやfa.jqueryはjquery.jsやjqueryui.js、その他cssなどが必要フロントのApacheやnginexに任せてしまいたいが、フォームライブラリが使うスタティックファイルはどこにあるのか?ウィジェットライブラリが依存するjsなどをどう管理していくか?
  43. 43. Paste deployでがんばr[app:deform_static]use = egg:paste#pkg_resourcesegg = deformresource_name = deform/static[composite:deform]use = egg:paste#urlmap/ = deform_app/static = deform_static[pipeline:deform_demo]pipeline = egg:repoze.tm2#tm deform
  44. 44. Fanstatic ● スタティックファイルをホスティングするWSGIアプリ ● スタティックファイルを管理するユーティリティ、ミドルウェア ● fa.jqueryは今後これを使うようになる予定http://pypi.python.org/pypi?%3Aaction=search&term=fanstatic&submit=search
  45. 45. Fanstatic 例from fanstatic import Fanstaticfrom js.jqueryui import jqueryui@wsgifydef app(request): jqueryui.need() return Response(body)app = Fanstatic(app)
  46. 46. Fanstatic 例body = """<html><head></head><body>Hello</body></html>"""
  47. 47. Fanstatic 例 実行結果<html><head> <script type="text/javascript" src="/fanstatic/jquery/jquery.js"></script><script type="text/javascript" src="/fanstatic/jqueryui/ui/jquery-ui.js"></script></head><body>Hello</body></html>
  48. 48. 参考● SQLAlchemy http://www.sqlalchemy.org/● ToscaWidgets http://toscawidgets.org/● formencode http://formencode.org/● Sprox http://sprox.org/● tw2 http://toscawidgets.org/documentation/tw2.core/● formalchemy http://docs.formalchemy.org/formalchemy● fa.jquery http://docs.formalchemy.org/fa.jquery/● WTForms http://wtforms.simplecodes.com/● colandar https://docs.pylonsproject.org/projects/colander/dev/● deform https://docs.pylonsproject.org/projects/deform/dev/● fanstatic http://www.fanstatic.org/en/0.11.2/index.html

×