Google App Engine には webapp という、Webアプリケーションのためのシンプルなフレームワークが用意されています。
前回はとりあえず Hello World まで行ったので、次はこの webapp フレームワークを使ってリクエストパラメータを受け取り、それを表示するアプリケーションを作ってみました。
私は Python 初心者のため、定石もお作法も知りません。バリバリの Python 使いの方から見たらとんでもないコードを書いているかもしれませんがご容赦下さい。間違いや「こうするもんだ」を指摘していただけるととても嬉しいです。
環境: Python 2.5
ソースコードを UTF-8 で書くには
ソースコードの1行目または2行目に
# coding: UTF-8
と書きます。
こうしないと、文字列リテラルの前には u'こんにちは' のように、毎回 u をつけないといけなくなってしまいます。それはあまりに面倒です。
HTTP post リクエストを受けるには webapp.RequestHandler を継承したクラスを定義し、post() メソッドを定義します。
(例)
class WelcomeRequestHandler(webapp.RequestHandler):
def post(self):
HTTP get リクエストを受けるには、post() ではなく get() メソッドを使えば OK です。使い方は post() と全く同一です。他にも、Restful なアプリケーション構築のために put() delete() head() trace() options() が用意されています。
※ Python って、メソッド?関数?どう呼ぶんでしょう?リクエストパラメータ値を取得するにはRequestHandler オブジェクトに用意されている属性 request の get() メソッドを利用します。引数にはリクエストパラメータ名を指定します。
(例)
userName = self.request.get('username')
これは、"username" という名前のリクエストパラメータ値を取り出し、変数 "userName" に入れておく、という処理になります。
リクエストパラメータが来なかった場合のデフォルト値を同時に指定することができます。
(例)
userName = self.request.get('username', default_value="anonymous")
上記の場合、リクエストパラメータ"username"が来なかった場合は変数"userName"の値が"anonymous"になります。
同名のリクエストパラメータが複数来る場合は
(例)
userNames = self.request.get('username', default_allow_multiple=True)
この場合、変数 userNames は配列になります。
レスポンスを出力するにはこう書きます(^^;
self.response.out.write('出力したい文字列')
変数の値を出力するにはこう書きます。
self.response.out.write(変数名.encode('文字エンコーディング名'))
これ、ハマりました。self.response.out.write(変数名) とするだけでは、実行時に UnicodeDecodeError とエラーになります。Python を使い慣れている方なら何でもないことなのでしょうけど・・・
リクエスト URL パターンと、実行するクラスを関連づけるにはこう書きます。
def main():
application = webapp.WSGIApplication([('URLパターン', クラス名)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
アプリケーションが起動したら main() 関数が呼ばれるようにするにはこう書きます。
if __name__ == "__main__":
main()
ある URL にリダイレクトするにはredirect() メソッドを使います。
self.redirect('http://www.google.co.jp/', False)
2番目の引数に True を指定すると、HTTP Status 301 での Redirect になります。False を指定した場合は HTTP Status 302 での Redirect を行います。
※Python の True/False って、大文字からはじめるんですね・・・例外発生時の処理を記述するにはRequestHandler クラスの handle_exception() メソッドを使うらしいのですが、使い方がよくわかりません・・・
以下、全ソースコード。
[index.html]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ようこそ!</title>
</head>
<body>
<form action="welcome" method="post">
<center>
<br />
<h3>お名前は?</h3>
<input type="text" name="username" size="30" />
<br /><br />
<input type="submit" value="送信" />
</center>
</form>
</body>
</html>
テキストボックスとsubmitボタンが一つずつあるだけのシンプルなフォームを実装した単純な HTML です。
[WelcomeRequestHandler.py]
# coding: UTF-8
import wsgiref.handlers
# webappのインポート
from google.appengine.ext import webapp
class WelcomeRequestHandler(webapp.RequestHandler):
# HTTP post リクエスト処理
def post(self):
# リクエストパラメータ "username" の取得
userName = self.request.get("username")
# レスポンス出力
self.response.out.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">')
self.response.out.write('<html>')
self.response.out.write('<head>')
self.response.out.write('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">')
self.response.out.write('<title>ようこそ</title>')
self.response.out.write('</head>')
self.response.out.write('<body>')
self.response.out.write(' <center>')
self.response.out.write(' <br />')
self.response.out.write(' <h3>ようこそ!')
# 変数値を出力する際には encode() 関数で処理する必要がある
self.response.out.write(userName.encode('UTF-8'))
self.response.out.write('さん!</h3>')
self.response.out.write(' <br /><br />')
self.response.out.write(' <a href="index.html">戻る</a>')
self.response.out.write(' </center>')
self.response.out.write('</body>')
self.response.out.write('</html>')
def main():
# リクエスト URL パターンと、実行するクラスの関連づけ
application = webapp.WSGIApplication([('/welcome', WelcomeRequestHandler)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
# アプリケーション起動時に main() 関数が実行されるようにする
if __name__ == "__main__":
main()
リクエストパラメータを受け取り、その値を使って「ようこそ!○○さん!」と出力するスクリプト。
[app.yaml]
application: liebejudith-helloworld
version: 1
runtime: python
api_version: 1
handlers:
- url: /welcome
script: WelcomeRequestHandler.py
- url: /index\.html
static_files: index.html
upload: index.html
- url: /
static_files: index.html
upload: index.html
/ あるいは /index.html が要求された場合は index.html を返し、/welcome が要求された場合は WelcomeRequestHandler.py が実行されるように設定しています。
app.yaml では、リクエスト URL パターンの関連づけを行いますが、.py スクリプトとの関連づけは、前回の Hello World で出てきました。
URL パターンと静的ファイルを関連づける場合は、static_files: エントリでファイル名を指定し、同時にサーバへアップロードするファイルを相対パスまたは絶対パスで指定します。
前回、「次回は掲示板でも・・・」なんて書きましたが、いきなり掲示板なんてとんでもなかったです。文字エンコーディングごときで大ハマリするぐらいですから。もっと少しずつ進めていきたいと思います。