09 4月 2008 ~ 0 Comments

Google App Engineを試す(1)

ピクチャ 15.png
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()

ピクチャ 16.png
作ってみたデータストアするゲストブック

本当はもっと簡潔にかけるのだろうけど、Pythonビギナーのため分かりません。とりあえずここで動作していることは確認済みです。とりあえず試してみた限りでは、

  • Python分かりづらいよPython
  • クラスを分けた方が良いよね
  • GQLってなんぞ
  • ローカルで開発している時もデータベースが使えるのがすごい
  • ついでに認証も使える。ただし任意のメールアドレス
  • routeの仕組みがもっと動的にできないものかな
  • 本格的な作り込みをしようと思うと、色々テクニックが必要そう

Pythonはインデントの強く意識して書かないと(当たり前ですが)いけないのが大変ですね。いつがクラスの終わりなのか、メソッドの終わりなのかが分かりづらい状態です。リクエストのハンドリングが多くなりがちなので、ここが自動的に振り分けられると便利かなぁ…。

GQLはO/Rマッピングを使えばあまり意識せずに使えるらしいですが、複雑な場合は覚えないといけないでしょうね。後、Ajaxを簡単に使えたりするのでしょうか。

最後にリリースです。リリースもCUIで行います。

$ appcfg.py update googleapps

にてファイルがアップロードされて、使えるようになります。

ファーストインプレッションはこのくらいで。可能性は多いにあると思いますので、ぜひ触ってみてください。

Leave a Reply

MOONGIFTネットワーク。こちらもぜひご覧ください。
MOONGIFT

Warning: array_slice() [function.array-slice]: The first argument should be an array in /virtual/producing/public_html/producing-web.com/wp-content/themes/network.php on line 15
  • No items
Open Service
Rails 2.0
Resident on Net
iPhone最適化
リーンソフトウェア
MarketPedia
Producing Web
Cool Coding