Google App Engine で1対多の結合をする
話題の Google App Engine ですが,やはり人気のようでまだアカウントが取得できていない人も多いようですね。アカウントがなくても,ローカルで開発は始められるので,これから始めようと思っている人は次の記事を参考にすると良いと思います(手前味噌ですが…)。
» 一番かんたんなGoogle App Engineの使い方 |gihyo.jp (技術評論社)

さて,本題の Google App Engine で1対多のジョインを行う方法に入っていきましょう。「BigTable」をバックエンドに利用できる Google App Engine ですが, RDBMS の考え方に慣れているとけっこう戸惑うことが多いです。 SQL に似た専用の GQL 言語は, OR や != が使えなかったりしてとても癖があります。親レコードと子レコードを JOIN する方法もわからずに最初は悩んだのですが,モデルを定義する際の ReferenceProperty に collection_name を定義しておくことで簡単にできます。正確には結合ではないかもしれませんが,親レコードから collection_name プロパティを参照することで関連する 子レコードのみを抽出することができるようになります。
以下のコードがそのサンプルになります。
# -*- coding: utf-8 -*-
import os,cgi
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template
class Group(db.Model):
name = db.StringProperty(required=True)
class Person(db.Model):
name = db.StringProperty(required=True)
age = db.IntegerProperty(required=True)
group = db.ReferenceProperty(Group,
required=True, collection_name='members')
class MainPage(webapp.RequestHandler):
def get(self):
# Group data
group1 = Group(name="Perfume")
group1.put()
group2 = Group(name="Puffy")
group2.put()
# Person data
person1 = Person(name=u"大本 彩乃", age=19, group=group1)
person1.put()
person2 = Person(name=u"樫野 有香", age=19, group=group1)
person2.put()
person3 = Person(name=u"西脇 綾香", age=19, group=group1)
person3.put()
person4 = Person(name=u"大貫 亜美", age=34, group=group2)
person4.put()
person5 = Person(name=u"吉村 由美", age=33, group=group2)
person5.put()
groups = Group.all()
path = os.path.join(os.path.dirname(__file__), 'example.html')
self.response.out.write(template.render(path, {'groups': groups}))
def main():
application = webapp.WSGIApplication(
[('/', MainPage)],
debug=True)
wsgiref.handlers.CGIHandler().run(application)
if __name__ == "__main__":
main()
アイドルがグループに所属するというモデルを考えます。大貫亜美さんと吉村由美さんは Puffy というグループに所属します。また,大本彩乃さん,樫野有香さん,西脇綾香さんは Perfume というグループに所属します。上のコードだと, Group と Person というモデルを定義して, MainPage クラスでデータを登録しています。そして, groups という変数に全てのグループを格納して,テンプレートに渡しています。
そして表示に利用するテンプレートは,これです。 Group ごとにループ処理を行い,さらにそのグループに所属するメンバーでループ処理を行っています。
{% for group in groups %}
<h2>{{ group.name }}</h2>
<ul>
{% for member in group.members %}
<li>{{ member.name }} ({{ member.age }}歳)</li>
{% endfor %}
</ul>
{% endfor %}
以上のプログラムを実行した結果は,次のようになります。

ちゃんと,グループごとに分かれて表示されていますね。









