Google App Engineを試す(1)

Google App Engineのプロジェクトページ
続くのかどうかは不安ですが。
とりあえずPythonもよくわかっていない(import文があること、インデントが重要ということくらいしか分からない)状態ではじめてみるのですが。Google App Engineのリファレンスを参考にすると、次の機能が使えるようです。
- ログインシステム
- データストア
- テンプレートエンジン
そこでゲストブックを参考に、機能を付け加えてみました。
まずありがちなHello Worldです。
適当な場所にgoogleappsというディレクトリを作成します。
$ mkdir googleapps
その中にapp.ymlと言うファイルを作成します。
$ cat googleapps/app.yml
ファイルを編集します。内容は以下のようになります。
application: moongift-sample
version: 1
runtime: python
api_version: 1
handlers:
- url: /.*
script: helloworld.py
ここで、application: の後はGoogle App Engineで取得した名称になります。Scriptは実行するスクリプトファイル名です。後はgoogleapps/helloworld.pyを作成し、次のように記述します。
print ‘Content-Type: text/plain’
print ”
print ‘Hello, world!’
これで実行すると、Hello, World!が出るはずです。
$ dev_appserver.py googleapps
INFO 2008-04-09 08:44:23,960 appcfg.py] Checking for updates to the SDK.
INFO 2008-04-09 08:44:24,451 appcfg.py] The SDK is up to date.
INFO 2008-04-09 08:44:24,485 dev_appserver_main.py] Running application moongift-sample on port 8080: http://localhost:8080
ということなので、localhost:8080にアクセスします。
では次のステップとして、フレームワークを使って処理をきちんと分けてみます。
フレームワークを使う場合は、以下のファイルをimportする必要があります。
import wsgiref.handlers
from google.appengine.ext import webapp
この状態で、次のように記述すると処理分けができます。
class MainPage(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, webapp World!')
def main():
application = webapp.WSGIApplication(
[('/', MainPage)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
if name == “main”:
main()
これを見て予想できる通り、http://localhost:8080/へのアクセスは、MainPageというクラスの処理に飛ばされます。そして、def getと書かれているのはgetアクセスした場合に呼ばれるもののようです。同様にdef postが使えます。ここによれば、put/delete/head/options/traceが使えるそうです。
次に認証処理です。これは、
from google.appengine.api import users
を頭に追記する必要があります。これだけでGoogle認証が利用できるようになります。そして、
user = users.get_current_user()
これでユーザ認証済みかどうかが分かります。
if user:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, ' + user.nickname())
else:
self.redirect(users.create_login_url(self.request.uri))
このように記述して処理分けできます。ごく簡単です。次はデータの受け渡しです。
self.request.get('content')
これでフォームからのデータが受けられるようです。もちろん、HTML側では
<form action=”/sign” method=”post”>
<div><textarea name=”content” rows=”3” cols=”60”></textarea></div>
<div><input type=”submit” value=”Sign Guestbook”></div>
</form>
のように記述されている必要があります。これもごくシンプルです。
最後がデータのストアです。これは
from google.appengine.ext import db
を追加した上で、新しいクラスを作成する必要があります。モデルのようなものです。
class Greeting(db.Model):
author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
このようなクラスです。これだけでデータベースが利用できるようになります。スキーマの定義を書いて実行して、といった手間がないのでごく簡単です。もちろん、開発環境(ローカル)でも使えます。
後は次のように呼び出して使うだけです。
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get('content')
greeting.put()
self.redirect('/')
greetingモデルを新しく作って、それにコンテンツを当てはめて、最後にputメソッドで保存処理を実行という流れです。これでゲストブックの流れが出来上がりです。実際のソースは以下のようになります。
#!-*- coding:utf-8 -*-
import cgiimport wsgiref.handlers
from google.appengine.api
import usersfrom google.appengine.ext
import webappfrom google.appengine.ext import db
class LogoutPage(webapp.RequestHandler):
def get(self):
self.redirect(users.create_logout_url(”/”))
class LoginPage(webapp.RequestHandler):
def get(self):
self.redirect(users.create_login_url(”/”))
class MainPage(webapp.RequestHandler):
def get(self):
self.response.out.write(’<html><body>’)
if users.get_current_user():
self.response.out.write(’<div><a href=”/logout”>Logout</a></div>’)
else:
self.response.out.write(’<div><a href=”/login”>Login</a></div>’)
greetings = db.GqlQuery(”SELECT * FROM Greeting ORDER BY date DESC LIMIT 10″)
for greeting in greetings:
if greeting.author:
self.response.out.write(’<b>%s</b> wrote:’ % greeting.author.nickname())
else:
self.response.out.write(’An anonymous person wrote:’)
self.response.out.write(’<blockquote>%s</blockquote>’ % cgi.escape(greeting.content))
# Write the submission form and the footer of the page
self.response.out.write(”"” <form action=”/sign” method=”post”> <div><textarea name=”content” rows=”3″ cols=”60″></textarea></div> <div><input type=”submit” value=”Sign Guestbook”></div> </form> </body> </html>”"”)
class Guestbook(webapp.RequestHandler):
def get(self):
self.redirect(’/')
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
else:
self.redirect(users.create_login_url(self.request.uri))
return
greeting.content = self.request.get(’content’)
greeting.put()
self.redirect(’/')
class Greeting(db.Model):
author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
def main():
application = webapp.WSGIApplication( [
('/', MainPage),
('/sign', Guestbook),
('/logout', LogoutPage),
('/login', LoginPage)
], debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == “__main__”: main()
本当はもっと簡潔にかけるのだろうけど、Pythonビギナーのため分かりません。とりあえずここで動作していることは確認済みです。とりあえず試してみた限りでは、
- Python分かりづらいよPython
- クラスを分けた方が良いよね
- GQLってなんぞ
- ローカルで開発している時もデータベースが使えるのがすごい
- ついでに認証も使える。ただし任意のメールアドレス
- routeの仕組みがもっと動的にできないものかな
- 本格的な作り込みをしようと思うと、色々テクニックが必要そう
Pythonはインデントの強く意識して書かないと(当たり前ですが)いけないのが大変ですね。いつがクラスの終わりなのか、メソッドの終わりなのかが分かりづらい状態です。リクエストのハンドリングが多くなりがちなので、ここが自動的に振り分けられると便利かなぁ…。
GQLはO/Rマッピングを使えばあまり意識せずに使えるらしいですが、複雑な場合は覚えないといけないでしょうね。後、Ajaxを簡単に使えたりするのでしょうか。
最後にリリースです。リリースもCUIで行います。
$ appcfg.py update googleapps
にてファイルがアップロードされて、使えるようになります。
ファーストインプレッションはこのくらいで。可能性は多いにあると思いますので、ぜひ触ってみてください。

