前回までの内容
リッチな 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 でのクライアント作成に入ります。
関連記事
- Google App Engine + Silverlight でタスク管理アプリケーション開発(1) - present
- Google App Engine + Silverlight でタスク管理アプリケーション開発(3) - present
- Google App Engine + Silverlight でタスク管理アプリケーション開発(4) - present
- Google App Engine + Silverlight でタスク管理アプリケーション開発(5) - present
- Google App Engine + Silverlight でタスク管理アプリケーション開発(6) - present