GoogleAppEngine

5. Google App Engine for Python でテンプレートを使う。

今回はテンプレートの使い方を試してみます。

WEBサイトを作るにあたって、デザイン部分とプログラム部分をわけることは管理をするうえで非常に重要なポイントとなります。サイトがシンプルなうちはまだいいのですが、複雑になるにつれメリットは大きくなります。このテンプレート機能はかなり充実してますが、全部を把握しょうとすると訳がわからなくなりますので、今回も最低限の機能だけ押さえます。

どのように分けるかというと、テンプレート部分でHTML上に変化される部分を置き、プログラム部分でその値を動的に変化をさせます。今回の出力結果は前回とまったく同じです。


#templateモジュールをインポートします。
import os
from google.appengine.ext.webapp import template

import cgi
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

class Message(db.Model):
  name = db.StringProperty()
  comment = db.StringProperty(multiline=True)
  date = db.DateTimeProperty(auto_now_add=True)

class MainPage(webapp.RequestHandler):
  def get(self):

    messages = db.GqlQuery("SELECT * FROM Message ORDER BY date DESC LIMIT 10")

    #テンプレート上で置き換える部分です。データストアの結果をそのまま使います。
    template_values = {
      'messages': messages
    }

    #テンプレートファイルへのパスです。
    #今回は同じディレクトリにindex.htmlというファイルをつくります。
    path = os.path.join(os.path.dirname(__file__), 'index.html')
    #template.render(テンプレートファイルへのパス, 変換する内容)という使い方です。
    self.response.out.write(template.render(path, template_values))

class Addcomment(webapp.RequestHandler):
  def post(self):
    message = Message()

    message.name = self.request.get('name')
    message.comment = self.request.get('comment')
    message.put()
    self.redirect('/')

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/add', Addcomment)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

続いて、テンプレートファイルの内容です。


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
  </head>
  <body>

      {% for message in messages %}
        {% if message.name %}
          {{ message.name|escape }} :
        {% else %}
          nanashi :
        {% endif %}
        {{ message.comment|escape }}
        ( {{ message.date }} )
        <br />
      {% endfor %}

    <form action="/add" method="post">
    <div>
        name<br />
        <input type="text" name="name" value=""></textarea>
    </div>
    <div>
        comment<br />
        <textarea name="comment" rows="3" cols="60"></textarea>
    </div>
    <div>
        <input type="submit" value="submit">
    </div>
  </form>
</body>
</html>

for message in messages という部分でデータストアでの検索結果について、ひとつづつループ処理をして行きます。内容は前回と同じですが、message.name がある場合はそのデータを、データがない場合はnanashiと表示します。|escape という部分はテンプレートの機能でページの表示を壊す可能性がある部分を置き換えます。

http://www.djangoproject.com/documentation/0.96/templates/#escape

ESCAPE
Escapes a string’s HTML. Specifically, it makes these replacements:

“&” to “&”
< to "<"
> to “>”
‘”‘ (double quote) to ‘"’
“‘” (single quote) to ‘'’

最後に投稿フォームを表示して完了です。

テンプレート部分を別にすることによってデザインとプログラム部分の分離ができました。これにより保守も楽にできるようになるのではと思います。

4. Google App Engine for Python のデータストアを使って簡単なゲストブックを作ってみる。

Google App Engineも第4回です、いよいよ今回はデータストアを使います。
しかし、Googleのドキュメントを読んでたのですが難しくてよくわかりません><

ですが最低限必要な知識だけでなんとか動くものを作る、それくらいだとなんとかなるものです。
本当に必要なものだけを使って簡単なゲストブックを作りたいと思います。ゲストブックに必要なものは「名前・コメント・時間」、これだけあればなんとかなります。目指すはこのシンプルなゲストブック!

スクリーンショット

Googel App Engineのデータストアでは、プログラムの中で定義をして利用するといった使い方になります。

それではデータストアに保存されるデータの定義部分です。

class Message(db.Model):
  name = db.StringProperty()
  comment = db.StringProperty(multiline=True)
  date = db.DateTimeProperty(auto_now_add=True)

db.Modelを継承したMessageクラスです。
また、データストアのデータオブジェクトをエンティティ、それぞれのデータの種類が設定された値をプロパティと呼びます。これらの用語の意味がわからないならスルーしても問題ありません。続けていくことによって、いつか「こういう意味なのか!」って瞬間がくるとおもいます。ぼくもよくわかってません><
StringProperty()、DateTimeProperty()などでそれぞれのデータを定義します。
multiline=Trueは改行を許可する、auto_now_add=Trueは現在時刻を自動で登録するなどのオプションとなります。

プログラムは、データとフォームを表示するMainpage部分とデータを追加するAddcomment部分です。


import cgi

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

#DBモジュールをインポートする
from google.appengine.ext import db

#モデル部分
class Message(db.Model):
  name = db.StringProperty()
  comment = db.StringProperty(multiline=True)
  date = db.DateTimeProperty(auto_now_add=True)

#データとフォームを表示する部分です。
class MainPage(webapp.RequestHandler):
  def get(self):
    self.response.out.write('<html><body>')

    #登録済みのデータの取得部分です。
    #SQLに似たGQLを使います、最新の投稿を10件取得します。
    messages = db.GqlQuery("SELECT * FROM Message ORDER BY date DESC LIMIT 10")

    #返って来たデータを一件ずつ処理して行きます。
    for message in messages:
      #もし名前が登録されていれば、その名前を表示。
      #登録されていなければnanashiと表示させます。
      if message.name:
        self.response.out.write('%s :' % cgi.escape(message.name))
      else:
        self.response.out.write('nanashi:')

      #コメントと日付を表示します 「名前:コメント(日付)」といったふうに表示されます。
      self.response.out.write(' %s ' % cgi.escape(message.comment))
      self.response.out.write(' (%s) <br />' % message.date)

    #登録済みのデータが表示されたら、フォームを表示します。
    #それぞれの項目名はモデルのname,commentと連動しています。
    self.response.out.write("""
          <form action="/add" method="post">
            <div>
                name<br />
                <input type="text" name="name" value="" cols="60"></textarea>
            </div>
            <div>
                comment<br />
                <textarea name="comment" rows="3" cols="60"></textarea>
            </div>
            <div>
                <input type="submit" value="submit">
            </div>
          </form>
        </body>
      </html>""")

#投稿されたデータをデータストアに登録する部分です。
class Addcomment(webapp.RequestHandler):
  #メソッドはPOSTです。
  def post(self):
    #messageはモデルクラスのインスタンスです。
    message = Message()

    #投稿されたデータを対応させます。
    message.name = self.request.get('name')
    message.comment = self.request.get('comment')
    #データの登録はput()だけですみます。すごい!
    message.put()
    #登録がすむと、通常ページにリダイレクトします。
    self.redirect('/')

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/add', Addcomment)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

データストアが出てくると、とたんに用語が増えて混乱してきます><
ですが、データを扱えるようになると世界が広がります。すこしづつ、すこしづつやって行きたいと思います。今回のエントリも用語の使い方について自信ありませんが、それでもなんとか動くものが作れました。まだまだGoogle App Engineの入り口にたったばかりです。なんとか、がんばります。

3. Google App Engine for Python でユーザからの送信されたデータを処理する。

google app engine。
3つめのエントリではユーザからの送信されたデータを表示するという単純なものです。
「<,>,&」が送信された場合に、そのまま表示してしまうとページが崩れてしまう恐れがありますので、pythonの標準ライブラリからCGIモジュールを使って置き換えをしています。

#pythonの標準ライブラリからcgiモジュールをインポートする。
import cgi

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class MainPage(webapp.RequestHandler):
  #メソッドがgetの場合
  def get(self):
    #出力
    self.response.out.write("""
      <html>
        <body>
          <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):
  #メソッドがpostの場合
  def post(self):
    self.response.out.write('<html><body>You wrote:<pre>')

    #cgi.escapeでポストされたcontentの「&,<,>」を置き換えて出力。
    self.response.out.write(cgi.escape(self.request.get('content')))

    self.response.out.write('</pre></body></html>')

#URLリクエストによって振り分ける。
#http://アプリケーションのURL/の場合はMainPage、
#http://アプリケーションのURL/signの場合はGuestbook。
application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/sign', Guestbook)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

CGIについてはpythonのサイトに詳細が載っています(英語)。
http://docs.python.org/library/cgi.html

Convert the characters ‘&’, ‘<' and '>‘ in string s to HTML-safe sequences. Use this if you need to display text that might contain such characters in HTML.

get()とpost()の2つを定義することで、それぞれのリクエストメソッドに対応した動作をすることが出来ます。

このデータをDBに登録すると、例えば掲示板やチャットのようなアプリケーションが作成できます。

2: Google App Engine for Python でUsersライブラリを使ってみる。

前回からだいぶ時間が空いてしまいました><
趣味のひとつとして、無料で遊べるGoogleAppEngineでプログラミングの勉強をしていきます。まったくわかんない状態からなんとか頑張ります。今回はUsersライブラリについて。

Google App Engine はUsersライブラリを利用すると Google Acountと連携できます。
Googleの解説ページを見ながらさっそくやってみます。
http://code.google.com/intl/ja/appengine/docs/python/gettingstarted/usingusers.html

Userライブラリはローカルの場合はテスト用の動作になるので注意が必要です。

#usersライブラリを使えるようにするためにインポートする。
from google.appengine.api import users

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class MainPage(webapp.RequestHandler):
  def get(self):

    #get_current_user()はGoogleにログインしていればUserオブジェクトを返す。
    #ログインしてなければNoneを返す。
    user = users.get_current_user()

    if user:
      #ログインしている場合

      self.response.headers['Content-Type'] = 'text/plain'
      #user.nickname()はニックネームです。
      #アカウントのメールアドレスとアプリケーションのドメインが一致しているかどうかで値が変わる。
      self.response.out.write('Hello, ' + user.nickname())

    else:
      #ログインしていない場合はログインページへとリダイレクトする。

      #self.request.uriを指定することで、ログイン後にこのページへと戻ってくる。
      self.redirect(users.create_login_url(self.request.uri))

application = webapp.WSGIApplication(
                                     [('/', MainPage)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

Userには次のメソッドがあります。

  • nickname()
  • email()
  • user_id()

nickname()はアプリのドメインとメールアドレスのドメインが同一かどうかで返す値が変わります。同一の場合は@の左側のみ、異なる場合はメールアドレス全体が返ってきます。
email()はメールアドレスが返ってきます。
user_id()は一意のIDを返します、これはユーザがアドレスを変更した場合でも変更されません。

Usersライブラリを利用すると、簡単にGoogleAcountを利用したサービスの作成が可能となります。

次:3. Google App Engine for Python でユーザからの送信されたデータを処理する。

1. Google App Engine でHello World!

pythonどころかプログラム自体がよくわかってないぼくが、GoogleAppEngineに興味をもったようです。いろんなサイトやGoogleAppEngineのドキュメントを読んでもいまいち頭に入ってこなかったのでここで整理しながらアウトプットしていきます。まずは単純出力、こんにちは世界!

#webappとはシンプルなウェブアプリケーションフレームワーク。
#これを使うといろいろな作業がサクッと出来る。
from google.appengine.ext import webapp

#run_wsgi_app()はアプリケーションが開発用サーバで実行されてる場合に
#ログとエラーを表示してくれる。
from google.appengine.ext.webapp.util import run_wsgi_app

class MainPage(webapp.RequestHandler):

    #HTTPリクエストに応じたメソッドが呼ばれる。
    def get(self):

        #ヘッダーをテキストにする。
        self.response.headers['Content-Type'] = 'text/plain'

        #HelloWorldを出力
        self.response.out.write('Hello, World!')

#リクエストをマッピング
#debug=Trueでデバッグモードになる
application = webapp.WSGIApplication(
                                    [('/', MainPage)],
                                    debug = True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()

次は、2: Google App Engine for Python でUsersライブラリを使ってみる。