GAE Django-nonrel

GAE/PythonでメジャーなフレームワークというとDjangoだけど、GAE用に改造されたDjango-patchは開発終了して新たにDjango-nonrelというのができています。
他のブログによると厳密にはGAE用ではなく”GAEでも動く”Djangoを作ろうというプロジェクトのようです。


さすがに新しいもののためかあまり情報がでていないようなので、本家のドキュメントを和訳してみました。
オリジナルの文章

11/14日現在の情報であること、オリジナルの文章の著作権Django-nonrelに帰属すること、自分の英語力は貧弱なのでところどころ意訳、省略がされていることにご注意ください。
4/4日の情報に更新しました。あと見やすく改編。


■Installation

App Engine SDKをインストールしてあることを確認して下さい。
ウィンドウズではシンプルにデフォルトのインストールパスを使います。
Linuxでは/usr/local/google_appengineを使います
マックではアプリケーションフォルダを使います
代わりに、すべてのシステムでSDKのフォルダを環境変数PATH(PYTHONPATHではない)に追加してもいいです。


  *django-nonrel (or clone it)
  * djangoappengine (or clone it)
  * djangotoolbox (or clone it)
  * django-dbindexer (or clone it)
  * django-testapp (or clone it)


これらのzipファイルをダウンロードしてください
すべて解凍してください


django-testappフォルダはあなたがスタートするためのサンプルプロジェクトです。
もし新しいプロジェクトを始るか、既存のDjangoプロジェクトを移植したいのなら、拡張子".py" と ".yaml"のすべてのファイルをルートフォルダからプロジェクトのフォルダにコピーし、settings.pyapp.yamlを必要に応じて編集することができます。


以下のフォルダをあなたのプロジェクトにコピーしてください。


  * django-nonrel/django => /django
  * djangotoolbox/djangotoolbox => /djangotoolbox
  * django-dbindexer/dbindexer => /dbindexer
  * djangoappengine => /djangoappengine


それで終わりです。プロジェクトの構成はこのようになっているはずです


  * /django
  * /djangotoolbox
  * /dbindexer
  * /djangoappengine


代わりに、もちろんそれぞれのレポジトリを複製してシンボルリンクを作成することでフォルダをコピーすることの代わりとすることもできます。
これは多くのプロジェクトがあってアップデートをひとつひとつ手作業でやりたくないときに、より簡単な方法になるでしょう。


■Management commands

直接Djangomanage.pyコマンドを使うことができます
例えば、manage.py createsuperuserを実行して新たな管理ユーザーを作成したり、manage.py runserverを実行して開発サーバーを開始したりしてください


重要:dev_appserver.pyを直接使わないでください。manage.py runserverがカスタマイズしたdev_appserver.pyの設定を使うので、期待した通りに動作しないでしょう。
同様に、manage.py ruserverを他の管理コマンドと同時に使わないでください。
変更は反映されないでしょう。これは最新のリリースで解決されるかもしれないがGAE SDKの制限です。


djangoappengineでいくつかmanage.pyコマンドが追加されています


  * manage.py remoteは製品のデータベースでコマンドを実行することを許可します。(例えば、manage.py remote shellmanage.py remote createsuperuser)
  * manage.py deployはあなたのプロジェクトをGAEにアップロードします(これをappcfg.py updateの代わりに使ってください)


manage.py remoteはあなたのアプリケーションがデプロイされ、App Engine Dashboard上のアプリ設定でGoogle Accounts APIを通して有効な認証があるときだけ使用できることに注意してください
同様に、もしあなたがカスタムしたapp.yamlを使っているならremote_apiハンドラが含まれていることを確認して下さい。


■Supported and unsupported features
■Field types

すべてのDjangoのフィールドは以下を除いて完全にサポートされます


  * ImageField
  * ManyToManyField


以下のフィールドオプションはGAEでは効果がありません



  * unique
  * unique_for_date
  * unique_for_month
  * unique_for_year


加えてdjangotoolboxはDjangoには無いフィールドを提供します
GAEや他の非リレーショナルなデータベースで以下のフィールドが使用可能です



  * ListField
  * BlobField


以下のGAEプロパティはDjango-nonrelのCharFieldでエミュレートされます



  * CategoryProperty
  * LinkProperty
  * EmailProperty
  * IMProperty
  * PhoneNumberProperty
  * PostalAddressProperty


■QuerySet methods

以下のフィールド検索をTextField(インデックスを使っていないなら)とBlobFieldを除いて行うことができます


  * __exact 等しい (デフォルト)
  * __lt より小さい
  * __lte より小さいか、等しい
  * __gt より大きい
  * __gte より大きいか、等しい
  * __in (プライマリーキーなら最大500件、他のフィールドなら最大30件)
  * __range 両方の境界に含まれる
  * __startswith 他のフィルターを結合する場合コンポジットインデックスが必要です
  * __year
  * __isnull ForeignKeyで正確に動作するにはdjango-dbindexerを要求します (この動作のためにインデックスを定義する必要はありません)


django-dbindexerを使うことで残りの検索タイプもまた自動的に動作するでしょう
加えて以下も使うことができます。



  * QuerySet.exclude()
  * Queryset.values() (only efficient on primary keys)
  * Q-objects
  * QuerySet.count()
  * QuerySet.reverse()
  * ...


すべての場合でGAEの標準的な制限を念頭におかなくてはいけません


モデルの継承は抽象基底クラスでのみ動作します

class MyModel(models.Model):
    # ... fields ...
    class Meta:
        abstract = True # important!

class ChildModel(MyModel):
    # works


一方で、複数テーブルの継承(例えば非抽象モデルからの継承)はクエリエラーとなるでしょう。
これは複数テーブルの継承は、その名の通り、継承関係のなかのそれぞれのモデルを分割テーブルで作成し、結果をJOINで結合する必要があるからです。
このことは抽象の親モデルを用いる限りサポートされる多重継承とは同じではありません。


多くのDjangoの高度な機能は現在のところサポートされていません


  * JOINs (django-dbindexerを使った簡単なJOINは動作するでしょう)
  * many-to-many relations
  * aggregates
  * transactions (しかしApp Engine's SDKrun_in_transaction()を使うことができます)
  * QuerySet.select_related()


■Other

加えて、以下のGAEの機能はサポートされていません


  * entity groups (我々はまだGAEPKFieldを分かっていませんが、それは追加するには些細なことです)
  * batch puts (技術的に可能ではあるけれど、まだだれも実装のための時間やその必要性を見つけられていません)


■Indexes

明示的にどのフィールドにインデックスを持たせる、持たせないを指定することができます。
これはまたTextFieldCharFieldのようなインデックスされたフィールドに変換できる可能性があります
この機能についての詳しいことは我々のブログに投稿された「Managing per-field indexes on App Engine」の記事で読むことができます。


■Email handling

GAEのメールAPIの代わりにDjangoのメールAPIを使うことができます(そして、使うべきです)。
GAEのEメールバックエンドはデフォルト設定ですでに使用可能です(from djangoappengine.settings_base import *)。
デフォルトで、Eメールは製品サーバーではバックグラウンドタスクまで延長(遅延)されるでしょう。


■Cache API

GAEのmemcacheモジュールの代わりにDjangoのキャッシュAPIを使うことができます(そして、使うべきです)。
memcacheのバックエンドはデフォルト設定ですでに使用可能です。


■Sessions

DjangoのセッションAPIを使うことができます、
cached_dbセッションバックエンドはデフォルト設定ですでに使用可能です。


■Authentication

django.contrib.authを直接使うことができます(そして、おそらくそうすべきです)。
我々はGAEのアカウントAPIを使うことを推奨しません。
これは不必要にGAEへの依存を高めます。代わりにDjangoの認証APIを使用してください。
もしあなたがGoogleアカウントをサポートしたいなら、OpenIDを用いることができます。
DjangoにはDjangoの認証APIを通してOpenID提供するさまざまなアプリがあります
これはまた将来的にYahooや他のログインオプションをサポートすることやGAEからの独立も見越すことができます。
グーグルアカウントのようにOpenIDでログインするサンプルは「Google OpenID Sample Store」を参照してください。


ユーザー名の一意性はフォームレベル(そして明示的に使用するならDjangoのモデル検証API)でのみチェックされることに注意してください。
GAEはDBレベルでの一意性の制約をサポートしていないので、可能性は殆どないとはいえ、ぴったり同時なら二人のユーザーが同じユーザー名で登録できてしまいます。
あなたの登録確認/有効化メカニズム(例えば、有効なアカウントでユーザーがメールを受け取るなど)はこのようなケースに正確に対処しなければいけません
例えば、活性化するモデルはそのユーザー名をプライマリーキーとして保存するなど。そうすれば作成したユーザーひとりだけ有効になるとおもって間違いありません。


■File uploads/downloads

BlobStoreとX-Sendfileとその他のソリューションで動作するFileFieldによる抽象的なファイルアップロード/ダウンロードAPIは「django-filetransfers」を参照してください。
必要とされるGAEのBlobStoreのバックエンドはデフォルト設定ですでに使用可能です。


■Background tasks

寄稿者:我々は抽象的にバックグラウンドタスクを扱いGAEやCeleryその他で同じコードで動作する実験的なAPIの開発を開始しました。


Please help us finish and improve the API here: https://bitbucket.org/wkornewald/django-defer
Please help us finish and improve the API here: https://bitbucket.org/wkornewald/django-defer


Make sure that your app.yaml specifies the correct deferred handler. It should be:

- url: /_ah/queue/deferred
script: djangoappengine/deferred/handler.py
login: admin


This custom handler initializes djangoappengine before it passes the request to App Engine's internal deferred handler.


(バックグラウンドタスクを扱うdjango-deferというAPIを作成中らしい。翻訳は省略)


■dbindexer index definitions

デフォルトでは、djangoappengine__iexactインデックスをUser.usernameUser.emailにインストールします。


■High-replication datastore settings

manege.py remoteをHigh-replication datastoreで使うためには、以下の設定をsettings.pyの先頭に加える必要があります

from djangoappengine.settings_base import *
DATABASES['default']['HIGH_REPLICATION'] = True


■App Engine for Business

manage.py remotegoogleplex.comドメインで使うためには、以下の設定をsettings.pyの先頭に加える必要があります

from djangoappengine.settings_base import *
DATABASES['default']['DOMAIN'] = 'googleplex.com'


■Checking whether you're on the production server

from djangoappengine.utils import on_production_server, have_appserver


製品サーバーで実行時、on_production_serverはTrueになります。
開発サーバーか製品サーバーで実行時、have_appserverはTrueになります


■Zip packages

重要:zipパッケージを使うとき、圧縮されたPythonファイルはプリコンパイルされないためにあなたのインスタンスは遅くロードされるでしょう
i18nもまたzipパッケージでは動作しないでしょう
圧縮は最後の手段であるべきです!もし3000ファイルの制限に引っかかった場合に最善なのはファイルの数を減らしてみることです。例えば、Djangoの"contrib"フォルダーから使用していないファイルを削除するなど。
他のやり方ではどうにもならないときだけ、zipパッケージを検討するべきです。


GAEに3000以上のファイルをアップロードできないため、ときどきzipパッケージを作る必要があります。
幸運にも、djangoappengineはこれらのzipパッケージを統合することで手助けすることができます
単純に"zip-packages"フォルダをあなたのプロジェクトフォルダに作成してzipパッケージをここに移動してください
これらは自動的にsys.pathに追加されるでしょう


簡単にzipパッケージを作成するためにはPython packageをひとつ選んで(例えばDjango app)これを圧縮することです。
けれども、Pythonのモジュールは透過的にこれらのzipファイルから読み込まれるということには留意してください。
例えば、zipパッケージからテンプレートやJavaScriptのファイルにアクセスすることは簡単ではありません。
テンプレートにアクセスできるようにするためには、Pythonパッケージを圧縮する前にテンプレートをプロジェクトのグローバルな"templates"フォルダに移動しなければいけません


■Contribute

If you want to help with implementing a missing feature or improving something please fork the source and send a pull request via BitBucket or a patch to the discussion group.