[GAE] Google App Engine で TODO アプリケーションを作ってみる
Getting Started Guide はなぞってみたので、今度は TODO アプリケーションを作ってみる。
Google App Engine で Tropy っぽいやつ作ってみた - IT戦記 を参考にしました。
うわっ Python のメソッドって self を引数に def するのか。モデルを定義 Todo クラス。done には BooleanProperty を使おう。
MainPage はログインしていなければログイン画面にリダイレクト。ログインしていれば、ログインユーザの Todo を取得して indext.html テンプレートを表示する。GQL を書くかわりに Mode の all, filter, order を使ってみる。
AddPage では get できたときは、追加ページテンプレート(add.html)を表示。post できたときは、リクエストパラメータから Todo を組み立ててデータストアに保存。日付は 20080426 形式での入力を想定。文字列から日付への変換はこれでいいのか。
DoneHandler は済のチェックボックスクリックで、id をもとに Todo を取得(get_by_id)して、done をトグルしてデータストアを更新。更新も登録と同じく put() で行なう。
DeleteHandler では DoneHandler と同じ。put() ではなく delete() を使う。
ま、こんなところか。
app.yaml
application: todo version: 1 runtime: python api_version: 1 handlers: - url: /.* script: todo.py
todo.py
# python2.5 ~/local/opt/google_appengine/dev_appserver.py ~/letter/gae/todo/ import cgi import os import time import datetime import wsgiref.handlers from google.appengine.api import users from google.appengine.ext import webapp from google.appengine.ext import db from google.appengine.ext.webapp import template #### モデル class Todo(db.Model): owner = db.UserProperty() content = db.StringProperty() deadline = db.DateProperty() done = db.BooleanProperty() #### メインページ class MainPage(webapp.RequestHandler): ### ログインしていない場合はログイン画面へ def get(self): if users.get_current_user(): self.list_todo() else: self.redirect(users.create_login_url(self.request.uri)) ### ログインユーザの TODO を取得してテンプレートへ def list_todo(self): todos = Todo.all().filter( "owner =", users.get_current_user()).order("deadline") path = os.path.join(os.path.dirname(__file__), 'index.html') logout_url = users.create_logout_url(self.request.uri) self.response.out.write( template.render(path, { 'todos': todos, 'logout_url': logout_url })) #### 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, {})) ### TODO をデータストアに保存して / にリダイレクト def post(self): todo = Todo() todo.owner = users.get_current_user() todo.content = self.request.get('content') todo.deadline = datetime.date( *time.strptime( self.request.get('deadline'), "%Y%m%d")[0:3]) todo.done = False todo.put() # データストアに保存 self.redirect('/') #### 済チェックボックスクリック class DoneHandler(webapp.RequestHandler): def get(self): todo = db.get(db.Key(self.request.get('key'))) todo.done = not todo.done todo.put() self.redirect('/') #### 削除ボタン class DeleteHandler(webapp.RequestHandler): def get(self): todo = db.get(db.Key(self.request.get('key'))) todo.delete() # データストアから削除する。 self.redirect('/') def main(): application = webapp.WSGIApplication( [('/', MainPage), ('/add', AddPage), ('/done', DoneHandler), ('/delete', DeleteHandler)], debug=True) wsgiref.handlers.CGIHandler().run(application) if __name__ == "__main__": main()
index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>TODO アプリケーション : Google App Engine</title> </head> <body> <h1>TODO</h1> <a href="/add">TODO 追加</a> <table> <tr> <th>内容</th><th>締切</th><th>済</th><th> </th> </tr> {% for each in todos %} <tr> <td>{{each.content}}</td> <td>{{each.deadline}}</td> <td><input type="checkbox" onclick="location.href='/done?key={{each.key}}'" {% if each.done %} checked{% endif %}></td> <td><input type="button" value="削除" onclick="location.href='/delete?key={{each.key}}'"></td> </tr> {% endfor %} </table> <a href="{{logout_url}}">ログアウト</a> </body> </html>
Model は key をパラメータにして、次のように取得する。http://code.google.com/appengine/docs/datastore/creatinggettinganddeletingdata.html
db.get(db.Key(self.request.get('key')))
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"> 内容 <input type="text" name="content"> 締切 <input type="text" name="deadline"> <input type="submit" value="追加する"> </form> <a href="/">キャンセル</a> </body> </html>