Flask にフォームがないから WTForms 使ってみた

AppEngine/Python では長らく Kay Framework を使っていたんですが、最近は Flask に浮気気味です。Flask は URL マッピングをビューのデコレーターで記述できるのがステキですよね。Kay だと作成したビューに割り当てる URL パターンを urls.py に書き忘れて、デバッグ時にうがーってなることがたまにあったんですが、Flask ではまず無いです。


そんな Flask の長所でもあり欠点でもあるのは、ビューとテンプレートだけなこと。モデルは自前で用意しなければいけません。しかし、もともと AppEngine/Python には db モジュールがあるから無問題。


…と思ってたら、フォームもありませんでした。忘れてた。AppEngine に標準で付いている django のフォームを使ってもいいんですが、WTForms を採用。

Flask Extensions には、WTForms をあたかも Flask に組み込まれているかのように使える拡張があります。

今回は素の WTForms を使いますけど。


フォームといったらもっぱら Kay のものばかり使っていたので、WTForms は使い勝手が違っていて戸惑いました。

# -*- coding: utf-8 -*-
from google.appengine.ext import db
from flask import (
    Flask, request, redirect,
    url_for, render_template,
)
from wtforms import (
    Form, TextField, TextAreaField,
)
from wtforms.validators import (
    Required, Length,
)

...

# モデル
class Entry(db.Model):
    title = db.StringProperty(required=True)
    content = db.TextProperty(required=True)
    created = db.DateTimeProperty(auto_now_add=True)

# フォーム
class EntryForm(Form):
    title = TextField(u"タイトル", validators=[
            Required(u"タイトルを入力してください"),
            Length(min=1, max=32, message=u"タイトルは32文字以内にしてください")
        ])
    content = TextAreaField(u"本文", validators=[
            Required(u"本文を入力してください")
        ])

# フォームを使って入力検証
@app.rotue("/entry/create", methods=["POST"])
def index():
    form = EntryForm(request.form)

    if form.validate():
        entry = Entry(title=form.title.data,
            content=form.content.data)
        entry.put()
        return redirect(url_for("index"))

    return render_template("entry_edit.html", form=form)

...

各 Field の validators パラメータで検証内容を指定するところがいいですね。Field と分離されているので、独自の検証内容を追加でき、さらには使い回せます。ソースを見たところ、検証で使うクラスを自作するのは難しくなさそうです。


んで、フォームを HTML で表示。

<html>
    <body>
        ...

        <!-- フォームを描画 -->
        <form method="POST" action="/entry/create">
            タイトル:<br/>
            {{ form.title() }}<br/>
            本文:<br/>
            {{ form.content() }}<br/>
            <input type="submit" value="公開"/>
        </form>

        ...
    </body>
</html>

Kay のフォームに慣れているせいか、form タグを使って HTML である程度フォームを記述しなければいけないのが、最初面倒に感じました。でも、フォームのラベルとかエラー表示とかをカスタマイズしようと思ったとき、Kay だと複雑な記述が必要だったので、これくらいシンプルな方がいいのかも。