GAE+django

pythonフレームワークであるdjango。非常に評価しているフレームワークのひとつである。DRYやルースカップリング等の設計哲学、非常にスマートな実装で素晴らしい。

しかしである。Google Application Engine(以下GAE)を久しぶりに動かしてみて考えたのだが・・・・。

「GAEではdjango以外の選択肢も考えたほうがいい」

と思った。

確かに以前と比べてdjangoのインストールは非常に簡単になっている。SDKをインストールした後、app-engine-patch-1.0.2.3.zipをダウンロードし、展開するだけである。
django本体はzip形式でパッチに含まれており、zipimportされるので別途インストールする必要はない。ネット上には0.9時代の情報が多く混乱した。ドキュメント読めばわかるのだが)

GAE SDK 1.3.1
http://code.google.com/intl/ja/appengine/downloads.html

app-engine-patch 1.0.2.3
http://code.google.com/p/app-engine-patch/

SDKGUIがついて、コマンドラインからmanege.pyを触らずともボタンひとつで開発サーバーが立ち上がる。いろいろと設定せずともEclipse+PyDevとSDKだけでさっとクラウド開発環境が作れるところまで出来ており、非常に手軽だ。

問題はここからである。
現在の時点ではこのGAE+djangoではdjangoのモデルが使えないのである。GAE+djangoではGAEで提供されるGoogleAPPのモデルを使用するしかない。そこで世界中の有志がGAEモデルで「djangoらしく」使えるようにと、様々なレベルの修正を行ったおかげで、リリース当初は使えなかったadminインターフェースも現在のバージョンではGAEモデルで使えるまでになっている。
しかし、そのおかげでパッチがパッチと呼べないほど肥大化してしまった。(本体が入っているパッチって・・)ここまでくるとパフォーマンスへの影響も大きくなってくる。
djangoはモデルの生成からform/validation、tempalte、そしてほぼ自動化された管理画面と、モデルを中心とした設計から最低限のコストで高品位なアプリを生成できるところが最大の魅力だ。モデル中心のフレームワークでモデルの構造が変わるわけだから、それは上記のような結果になるのも当然である。

GAEのモデルが悪いわけではない。それどころかdjango+patchでは「GAEモデルの強力な部分が生かされない」ところが問題なのだろう。触ったことがあるひとならわかると思うが、GAEのモデルはRDBにはない拡張が行われている。動的プロパティ(カラム)やテーブルの継承(Postgres等でサポートされているものに近い)が行える。RDBというよりオブジェクトデータベースのほうに近い実装となっている。これら2つの機能を独自に実装したRDBは既にあるが、GAEのようなオープンなクラウド環境で提供されているという点では大きな違いといえる。

上記2つの機能はモデル設計を劇的に変える。例えば継承を使えば以下のようなモデルを作れる。

from google.appengine.ext import db
from google.appengine.ext.db import polymodel
from google.appengine.api import users
from datetime import datetime

class BusinessObject(polymodel.PolyModel):
    creation_date = db.DateTimeProperty()
    creation_user = db.UserProperty(auto_current_user_add=True)
    modification_date = db.DateTimeProperty()
    modification_user = db.UserProperty(auto_current_user=True)
    def __unicode__(self):
        return self.key()
    def save(self):
        if self.is_saved() == False:
            self.creation_date = datetime.now()
        self.modification_date = datetime.now()
        super(BusinessObject, self).save()

class Contact(BusinessObject):
    title = db.StringProperty(required=True)
    caption = db.StringProperty()
    phone = db.PhoneNumberProperty()
    fax = db.PhoneNumberProperty()
    postal_code = db.StringProperty()
    address = db.PostalAddressProperty()
    def __unicode__(self):
        return self.title

class Company(Contact):
    url = db.StringProperty()

class Person(Contact):
    last_name = db.StringProperty(required=True)
    first_name = db.StringProperty(required=True)
    last_name_caption = db.StringProperty()
    first_name_caption = db.StringProperty()
    mail = db.EmailProperty()
    mobile_phone = db.PhoneNumberProperty()
    url = db.StringProperty()
    def save(self):
        self.title = '%s %s' % (self.last_name, self.first_name)
        self.caption = '%s %s' % (self.last_name_caption, self.first_name_caption)
        super(Person, self).save()

上記のモデルはPerson及びCompanyはContactとしても扱われる。PersonやCompanyにクエリを実行すればそれぞれが返されるのは当然だが、Contactにクエリを実行するとCompany、Person及びContactを全てを含めて返される。もちろんこれらのオブジェクトは全てBusinessObjectの内容も継承している。(GAEで提供される管理画面からデータベースをのぞくと、これら全てのデータはBusinessObjectのテーブルに含まれている。ちなみに現時点では継承と動的プロパティを同時に使うことはできない。)

app-engine-patchのサイトでもトップページで以下のように述べている。

We might also recommend that you check out the Kay Framework if you're looking for a very django-like framework that is built specifically for App Engine (no Object To Relational To Object data mapping issues or other monkey-patch warts).

「とてもdjangoライクでGAEに特化して作ったKayフレームワークもあるよ。チェックしてね(モデルリレーションの問題やぐちゃぐちゃなパッチもないよ)」

Kay Framework
http://code.google.com/p/kay-framework/

もちろん、djangoの優れた設計哲学のおかげで、パーツとしての活用(特にテンプレート)は有用だろう。しかしながら上記のようなデータ構造の違いやパフォーマンスの問題も大きい。(処理負荷で課金するクラウドではなおさらだ)

djangoは「djangoらしく」、GAEでは「GAEらしく」というアプローチのほうが正しいのだろう。


ある程度理解している人向けですが、よくまとめられていてます。他の言語もやっててPythonやってみようかなという人には特にお勧めです。Pythonは日本語ドキュメントが少ないって昔は言われていたんですが、最近は増えましたね。

Django Reinhardt In Ro

Django Reinhardt In Ro

ちなみに、表紙の人はジャンゴ・ラインハルトさん。djangoの名前の由来になった人です。