アドベントカレンダーにコッソリ登録したつもりだったのに、 id:kuenishi から翌日に指名されてしまった @tokibito です。
今日はAppEngineで書きます。最近仕事でも少し触ってます。
他の人みたいにボリュームたっぷりの記事は書けないので軽めに。
モデルから辞書にデータをマッピングするのに便利なbpmappersを、AppEngineのwebappフレームワークで使う例を書きます。
SDKのバージョンは1.4.0です。
bpmappers 0.8.2 : Python Package Index
bpmappersを使えるようにする
Google App Engine Launcher で新規アプリケーションを作成します。
bpmappersのtarballをダウンロード、展開して中のbpmappersディレクトリをアプリケーションのディレクトリにコピーします。
コードを書く
実装するもの
- nameとageを持ったPersonモデルを扱う
- "/" でGETすると、nameとidの一覧を返す
{"people": [{"id": 1, "name": "tokibito"}, {"id": 1001, "name": "test"}]}
- nameとageをPOSTするとデータを追加する
- GETパラメータにid=123のように指定すると指定IDのid,name,ageを返す
{"id": 1, "name": "tokibito", "age": 25}
models.py
Personモデルを作ります。
from google.appengine.ext import db class Person(db.Model): name = db.StringProperty(required=True) age = db.IntegerProperty()
forms.py
POST時のデータ検証と保存にModelFormを使います。
from google.appengine.ext.webapp import template from google.appengine.ext.db import djangoforms from models import Person class PersonForm(djangoforms.ModelForm): class Meta: model = Person
mappers.py
Personのマッピング用クラスを作ります。
from bpmappers import Mapper, RawField, ListDelegateField class PersonSummaryMapper(Mapper): id = RawField('key', callback=lambda v: v.id()) name = RawField() class PersonMapper(PersonSummaryMapper): age = RawField() class PeopleMapper(Mapper): people = ListDelegateField(PersonSummaryMapper)
main.py
# coding: utf-8 try: import simplejson except ImportError: from django.utils import simplejson from google.appengine.ext import webapp from google.appengine.ext.webapp import util class MainHandler(webapp.RequestHandler): def initialize(self, request, response): super(MainHandler, self).initialize(request, response) self.response.headers['Content-Type'] = 'application/json; charset=utf-8' def get(self): """ idが指定されていれば詳細 そうでなければサマリーで一覧を返す """ from models import Person from mappers import PersonMapper, PeopleMapper obj_id = self.request.get('id') if obj_id: person = Person.get_by_id(int(obj_id)) if person: result_dict = PersonMapper(person).as_dict() else: result_dict = {'response': 'Does not exist.'} else: people = Person.all() result_dict = PeopleMapper(dict(people=people)).as_dict() self.response.out.write(simplejson.dumps(result_dict)) def post(self): """ データの追加 """ from forms import PersonForm form = PersonForm(self.request.POST) if form.is_valid(): person = form.save() result_dict = {'response': 'OK'} else: result_dict = {'response': 'Invalid'} self.response.out.write(simplejson.dumps(result_dict)) def main(): application = webapp.WSGIApplication([('/', MainHandler)], debug=True) util.run_wsgi_app(application) if __name__ == '__main__': main()
最終的なファイル構成
>tree /F . │ app.yaml │ forms.py │ index.yaml │ main.py │ mappers.py │ models.py │ └─bpmappers djangomodel.py fields.py mappers.py utils.py __init__.py
動かしてみる
AppEngine LauncherのRunボタンをクリックして起動しました。dev_appserver.pyで起動してもよいです。
データを投入するためにPOSTを行わないといけないですが、Firefox拡張のPosterを使うと便利です。
Poster :: Add-ons for Firefox
もしくはPOST用のフォームを書いたHTMLファイルから行います。
<form action="http://localhost:8080/" method="post"> name: <input type="text" size="30" name="name" /><br/> age: <input type="text" size="5" name="age"/><br/> <input type="submit"/> </form>
データを投入したあと、参照用のURLにアクセスするとJSON形式のデータを得られます。
おわりに
次は、最近仕事でもお世話になっている @shimizukawa に頼みます。素敵な記事に期待!