Google App Engine + Silverlight でタスク管理アプリケーション開発(2)

前回までの内容

リッチな UI を持つ Web アプリを作った事がないので、GAE + Silverlight で作ってやろうという本連載。

前回は作成するアプリの詳細を決めて、GAE のプロジェクトを作成するところまで済ませました。済ませたといっても、せいぜい準備程度で、本番はこれからなんですけどね。

今回はモデルとビューを作成していきます。

モデルの作成

core/models.py に モデルクラスを追加します。

CRUD 操作を行うメソッドをモデルに実装しておいて、ビューからはメソッドを呼び出すだけにしておきます。こうしておけば、ビューの肥大化を防げますし、単体テストもしやすい。

Kay はビューのテスト方法も提供していますけど、それでもビューのテストって面倒ですからね。

# -*- coding: utf-8 -*-
from google.appengine.ext import db
from kay.db import OwnerProperty
from kay.utils import get_or_404

DATETIME_FORMAT = "%Y/%m/%d %H:%M:%S"

class Task(db.Model):
    user = OwnerProperty()
    name = db.StringProperty(required=True)
    done = db.BooleanProperty(default=False)
    created = db.DateTimeProperty(auto_now_add=True)

    def __unicode__(self):
        return self.name

    def to_dict(self):
        user_key = ""
        if self.user:
            user_key = str(self.user.key())
        return {
            "key": str(self.key()),
            "user": user_key,
            "name": self.name,
            "done": self.done,
            "created": self.created.strftime(DATETIME_FORMAT),
        }

    @classmethod
    def read_tasks(cls, user_key, params={}):
        done = cls._get_done_parameter(params)
        return cls.all()\
               .filter("user =", user_key)\
               .filter("done =", done)\
               .order("-created")

    @staticmethod
    def _get_done_parameter(params):
        done = False
        done_string = params.get("done")
        if done_string:
            if done_string == "True":
                done = True
        return done

    @classmethod
    def create_task(cls, data):
        task = cls(name=data["name"])
        key = task.put()
        return cls.get(key)

    @classmethod
    def delete_task(cls, key):
        task = get_or_404(cls, key)
        task.delete()
        return task

    @classmethod
    def update_task(cls, key, data={}):
        task = get_or_404(cls, key)
        for key, val in data.iteritems():
            if hasattr(task, key):
                setattr(task, key, val)
        task.put()
        return task

to_dict メソッドはモデルを JSON に変換するときに利用します。GAE/Python で使える simplejson モジュールは、モデルクラスを直接 JSON に変換できないので、このメソッドで dict に変換して、それから JSON に変換するのです。

ビューの作成

core/views.py にビュー関数を追加します。ビューの役割は、リクエストを受けたらモデルのメソッドを呼び出し、結果を JSON にして返すだけです。

RESTful な API にするので、何でもかんでも POST で処理しません。更新には PUT、削除には DELETE を使います。

# -*- coding: utf-8 -*-
from werkzeug import (
  Response,
)
from kay.utils import (
  render_to_response, url_for,
  render_json_response, get_or_404
)
from kay.auth.decorators import login_required
from core.models import (
    Task
)
import simplejson

@login_required
def index(request):
  return render_to_response('core/index.html', {})

def tasks(request):
    if request.method == "POST":
        task = Task.create_task(request.form)
        return render_json_response(task.to_dict())
    tasks = Task.read_tasks(request.user.key(),
                            params=request.args)
    data = [task.to_dict() for task in tasks]
    return render_json_response(data)

def task_detail(request, key):
    if request.method == "DELETE":
        Task.delete_task(key)
        return Response(key)
    if request.method == "PUT":
        model_dict = simplejson.load(request.stream)
        task = Task.update_task(key, model_dict)
    else:
        task = get_or_404(Task, key)
    return render_json_response(task.to_dict())

更新の実装に手こずりました。PUT を使った例が全然見つからず、海外のブログやフォーラムを漁って、なんとか実装できましたけど。

Kay はユーティリティ関数をたくさん提供しているので、かゆい所に手が届きます。get_or_404 や render_json_response は便利。自分でユーティリティ関数を作成する前に、Kay で提供されていないか探してみるといいです。

そうそう、せっかく作成したビューも、登録しなければ意味ないので、core/urls.py を編集しておきます。

# -*- coding: utf-8 -*-
from kay.routing import (
  ViewGroup, Rule
)

view_groups = [
  ViewGroup(
    Rule('/', endpoint='index', view='core.views.index'),
    Rule('/tasks', endpoint='tasks', view='core.views.tasks'),
    Rule('/tasks/<key>', endpoint='task_detail', view='core.views.task_detail'),
  )
]

今回はここまで

今回の変更内容の詳細は、下記のページで確認できます。

記事本文には載せてないですが、モデルとビューの単体テストもあります。Kay はモデルやビューをテストする方法を提供しているので、サクっとテストが書けます。もう webapp には戻れません。

これでサービス側はひとまず完成です。次回からいよいよ(?)、Silverlight でのクライアント作成に入ります。