GAEpでiPhone向けWebアプリを作る (7)リクエストハンドラをを実装していく

前回の続きです。

リクエストハンドラを実装していく

続いて、GAEp のリクエストハンドラを実装していきます。

各実装ごとに部分的に書いていきます。

MainView の実装

MainView#get() では、単純に html を出力します。

todo/handlers.py内

import os
from google.appengine.ext.webapp import template

# 中略

#
class MainView(webapp.RequestHandler):
  #
  def get(self):
    s_tplpath = 'templates/views.tpl'
    path = os.path.join(os.path.dirname(__file__), s_tplpath)
    self.response.out.write(template.render(path, {}))
  • templates/views.tpl という名称のテンプレートファイルを http レスポンスとして出力しています。
  • テンプレートファイルと言いつつ、実はテンプレートではなく、html ファイルそのものです。データを埋め込みません。render() メソッドの第2引数は空オブジェクトです。
  • templates/views.tpl は、staticdir/views.html のシンボリックリンクになっています。
  • staticdir/views.html には、すべてのビューが含まれています。これは次回以降に。

GAEp のテンプレートエンジンは、デフォルトでは django のテンプレートエンジンとなっています。django のテンプレートエンジンのリファレンスは以下。

サーバサイドのテンプレートエンジンを利用したビューとモデルのバインディングはそれはそれでパワフルですが、今回はバインディングはクライアントサイドの javascript で行います。なので、ここで返すのは静的ファイルのみです。

ToDoList の実装

続いて、ToDoList#get() の実装です。

todo/handlers.py内

import logging
from google.appengine.ext import webapp
from google.appengine.api import users
from django.utils import simplejson as json
from todo.models import ToDoItem

# 〜〜〜

#
class ToDoList(webapp.RequestHandler):
  #
  def get(self):
    logging.debug('ToDoList#get')
    data = None
    user = users.get_current_user()
    if user:
      userinfo = {
        'nickname': user.nickname(),
        'logout_url': users.create_logout_url('/todo/bye.html')
      }
      q = ToDoItem.all()
      q.filter('owner =', user)
      q.order('deadline')
      results = q.fetch(20)
      itemlist = [{
          'key':str(item.key()),
          'title':item.title, 
          'detail':item.detail, 
          'deadline':item.deadline.strftime('%Y-%m-%d'),
        } for item in results]
      data = {
          'userinfo': userinfo,
          'items': itemlist,
        }
    self.response.content_type = 'application/json'
    json.dump(data, self.response.out, ensure_ascii=False)
    return

import 文は、この部分に必要なものだけ書いています。

処理の流れは以下です。

  1. アクセスしている人がログイン済み(user != None)だったら、
  2. そのユーザの20件の ToDo アイテムを古いものから検索し、レスポンス用オブジェクト(itemlist)に変換し、
  3. ToDo アイテム(itemlist)とユーザ情報(userinfo)をひとまとめ(data)にして
  4. JSON データとして http レスポンスに出力

アクセスしている人がログイン済みのユーザかどうかは、User クラスのインスタンスを取得することで確認できます。

    user = users.get_current_user()
    if user:
      userinfo = {
        'nickname': user.nickname(),
        'logout_url': users.create_logout_url('/todo/bye.html')
      }

取得は、google.appengine.api.users パッケージの get_current_user() 関数で行います。
リファレンスは以下です。

user != None ならログイン済み、そうでなければログインしていません。
また、ログアウト URL は、同じパッケージの create_logout_url() 関数で作成できます。この URL にアクセスすることで、ユーザはログアウトできます。引数には、ログアウト後のリダイレクト先 URL を指定できます。

以下の部分で、ユーザの ToDo アイテムを締め切りの古いものから20件検索しています。

      q = ToDoItem.all()
      q.filter('owner =', user)
      q.order('deadline')
      results = q.fetch(20)

で、検索結果をレスポンス用オブジェクト(itemlist)に変換しています。

      itemlist = [{
          'key':str(item.key()),
          'title':item.title, 
          'detail':item.detail, 
          'deadline':item.deadline.strftime('%Y-%m-%d'),
        } for item in results]

itemlist はディクショナリオブジェクトのリストです。ひとつの ToDo アイテムは、ひとつのディクショナリオブジェクトで表し、以下を持っています。

key
ToDo アイテムのキー。これには、ToDoItem エンティティのキーをそのまま利用する。
title
ToDoItem エンティティの title プロパティ(ToDo タイトル)の値
detail
ToDoItem エンティティの detail プロパティ(ToDo 内容詳細)の値
deadline
ToDoItem エンティティの deadline プロパティ(この ToDo の締め切り)の値。"2011-06-05" のように"年-月-日" という書式で。

で、最後に、ユーザ情報(userinfo)と ToDo アイテムのレスポンス用オブジェクト(itemlist)をひとつのオブジェクト(data)にまとめ、JSON 形式で http レスポンスに書き出しています。

      data = {
          'userinfo': userinfo,
          'items': itemlist,
        }
    self.response.content_type = 'application/json'
    json.dump(data, self.response.out, ensure_ascii=False)

GAEp には simplejson が入っているので、それを利用しています。ちょー簡単です。

長くなったので今回はここまで。

参考

Google App Engine については、基本的に Google が公開しているデベロッパーガイドを見ればだいたいのことはわかります。内容もわかりやすいです。

基本的にはこれらのサイトを見ればほとんどのことはわかりますが、その他に僕は以下の本を参考にしています。

Programming Google App Engine

Programming Google App Engine

和訳も出ているようです。

プログラミング Google App Engine

プログラミング Google App Engine