The Django Form Validation Framework on Google App Engine

Django Form Validation Framework を Google App Engine で使ってみる。

インポート

この前のTODO アプリケーション でやってみる。

djangoforms をインポートするが

from google.appengine.ext.webapp import template

の後ろで

from google.appengine.ext.db import djangoforms

とインポートする。

フォームクラスの定義

djangoforms.ModelForm を派生したクラス。Meta サブクラスでモデルとフォームに表示しないプロパティを指定する。exclude のかわりに fields と使うと表示するプロパティの指定もできる。
auto_now, auto_now_add が指定してあるものは自動的にフォームには表示されないらしい。
フォーム表示時には default によって初期値が設定される。choices はドロップダウンになる。

#### フォームクラス
class TodoForm(djangoforms.ModelForm):
    class Meta:
        model = Todo            # モデル指定
        exclude = ['owner']     # フォームに不要なプロパティリスト

モデルに verbose_name を指定しておくとそれをフォームの項目名に表示してくれる。

#### モデル
class Todo(db.Model):
    owner = db.UserProperty()
    content = db.StringProperty(verbose_name='内容', required=True)
    deadline = db.DateProperty(verbose_name='締切容', required=True)
    done = db.BooleanProperty(verbose_name='済')

フォームを使う

TodoForm() とすれば、フォーム部分が生成されるらしい。生成されるフォームは tr タグからなので table タグで囲む必要がある。
ポストされたものは data = TodoForm(data = self.request.POST) で取得でき、data.is_valid() で検証が走る。
data.save でモデルが返ってくる。commit=False を指定しない場合はこの時点でデータストアに保存される。ここでは owner を設定したいので commit=False とし、owner 設定後に put する。
検証失敗時は data をそのまま表示すればエラーメッセージ付きのフォームが生成される。

#### TODO 追加ページ
class AddPage(webapp.RequestHandler):
    ### TODO 追加ページのテンプレートへ
    def get(self):
        path = os.path.join(os.path.dirname(__file__), 'add.html')
        self.response.out.write(template.render(path, {'form': TodoForm()}))

    ### TODO をデータストアに保存して / にリダイレクト
    def post(self):
        data = TodoForm(data = self.request.POST)
        if data.is_valid():
            ## 入力エラーなし
            todo = data.save(commit=False) # owner をセットするので commit=False
            todo.owner = users.get_current_user()
            todo.put()          # ここでデータストアに
            self.redirect('/')
        else:
            ## 入力エラーあり
            path = os.path.join(os.path.dirname(__file__), 'add.html')
            self.response.out.write(template.render(path, {'form': data}))

add.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>TODO 追加ページ</title>
  </head>

  <body>
    <h1>TODO を追加します</h1>

    <form action="/add" method="post">
      <table>
      {{form}}
      </table>
      <input type="submit" value="追加する">
    </form>

    <a href="/">キャンセル</a>
  </body>
</html>

その他

  • エラーメッセージのカスタマイズ(日本語化)はどうやるんだろう?
  • 値が None のものがあると order できない?
  • モデルの default はその値がキャッシュされているので users.get_current_user() 等は指定できない。__init__() で初期化する。