app-engine-patchを使ってみた(GoogleAppEngine)

GAEをちょこちょこ弄っているんですが、標準のwebappはWebアプリ用のフレームワークとしては貧弱ですので、Djangoを使ってみる事にしました。で、DjangoはGAEにも標準で組み込まれているのですが、どうやらそのままだと色々制限が強く、代わりにapp-engine-patchというDjangoをGAE用に修正したパッケージを使うのが良さそうです。

以下のその手順のメモになります。理解度が低いので間違ってるかもですが。

やること

  1. インストール
  2. 整理
  3. adminユーザの作成
  4. HelloWorldアプリ作成
  5. 本番サーバにアップロード

1. インストール
app-engine-patchは幾つかのサンプルアプリと一緒にサンプルパッケージとして配布されているので、インストールは非常に簡単でzipパッケージをダウンロードして適当なディレクトリに解凍するだけです。解凍したディレクトリ内のmanage.pyというスクリプトでサーバを起動します。(dev_appserver.pyは使わない)

$ wget http://app-engine-patch.googlecode.com/files/app-engine-patch-1.0.2.3.zip
$ unzip app-engine-patch-1.0.2.3.zip
$ cd app-engine-patch-sample
$ chmod u+x manage.py
$ ./manage.py runserver

ブラウザからhttp://localhost:8000/にアクセスします。ページが表示されたら成功です。

2. 整理
app-engine-patchはサンプルパッケージとして配布されているので、いらないファイル、設定、プラグインが入っています。もちろんそのままサンプルパッケージにアプリを追加していっても良いのですが、気持ち悪いので整理します。配布元のドキュメントにマニュアルインストールの方法というのもあるのですが、ここではサンプルパッケージがら必要なファイルをコピーして使う事にしました。

myprojectディレクトリを作成し、app-engine-patch-sampleから以下のファイル群をコピーしました。

  + myproject
    + common
    + _generated_media
    - manage.py
    - app.yaml
    - settings.py
    - urls.py
    - __init__.py
    + templates     # 自分で作成 (後述)
       - index.html # 自分で作成 (後述)

次にapp.yaml, settings.py, urls.pyをそれぞれ整理します。なお、app.yamlはGAEの設定ファイル、settings.pyはDjangoの設定ファイル, urls.pyはurlとviewのマッピングファイルです。また、settings.pyは出来るだけシンプルにしたつもりですが自信がありません。間違ってたら教えて下さい。

app.yaml

application: GAEに登録しているアプリの名前
version: 1
runtime: python
api_version: 1

default_expiration: '3650d'

handlers:
- url: /media
  static_dir: _generated_media
  secure: optional

- url: /.*
  script: common/appenginepatch/main.py
  secure: optional

settings.py

# -*- coding: utf-8 -*-
from ragendja.settings_pre import *

MEDIA_VERSION = 1

# ここは修正して、誰にも知らせたら駄目
SECRET_KEY = '123456789'

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.core.context_processors.auth',
    'django.core.context_processors.media',
    'django.core.context_processors.request',
    'django.core.context_processors.i18n',
)

MIDDLEWARE_CLASSES = (
    'ragendja.middleware.ErrorMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.locale.LocaleMiddleware',
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.sessions',
    'django.contrib.admin',
    'appenginepatcher',
    'ragendja',
)

from ragendja.settings_post import *

urls.py

# -*- coding: utf-8 -*-
from django.conf.urls.defaults import *
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns('',
    ('^admin/(.*)', admin.site.root), # 管理インタフェースへ
    (r'^$', 'django.views.generic.simple.direct_to_template', {'template': 'index.html'}),
)

次にindex.htmlを作って、アクセスしてみます。myprojectの直下にtemplatesディレクトリを作成し、その中にindex.htmlを作成します。index.htmlはDjangoテンプレートとして扱われますが、ここでは普通のhtmlを作成しました。


  
    

hello app-engine-patch!

先ほどと同じくmanage.pyを使用してサーバを起動してブラウザからアクセスしてみます。http://localhost:8000/にアクセスしてindex.htmlが表示されたら成功です。

3. adminユーザの作成
app-engine-patchでは、デフォルトでGAEに組み込まれているDjangoでは使えない管理インタフェースが使用できます。ですが、最初は管理インタフェースにログインする為のユーザが設定されていないので、ユーザを作成する必要があります。

GAEはバックエンドがRDBではないので、ちょっとしたデータをDatastoreに保存するのも結構厄介なのですが、app-engine-patchにはpythonシェルで直接サーバを叩く機能がありますので、ここではそれを使ってユーザを登録します。

./manage.py shellでシェルを起動した後に以下を入力します。
(username, password) = (‘admin’, ‘admin’)のログインユーザを作成しています。
サーバが起動中の場合は、登録したデータをロードする為に再起動が必要です。

# ./manage.py shellでpythonシェルを起動
>>> from django.contrib.auth.models import User
>>> user = User(username='admin', is_superuser=True, is_staff=True)
>>> user.set_password('admin')
>>> user.put()

早速管理インタフェースにアクセスしてみます。ブラウザでhttp://localhost:8000/adminにアクセスすると、ログインフォームが出るので、先ほど作成したユーザでログインします。無事にログインできましたね!

4. HelloWorldアプリ作成
上記の1,2,3でapp-engine-patchを使う準備ができました。折角なので動作確認の為に,軽くテストアプリを作ってみました。

作成するのは本のリストアプリです。管理画面から登録した本のリストを表示するだけの小さなプログラムですが、動作確認には十分ですね。

手順は以下のようになります。僕はDjangoを使うのは初めてなのですが、手元の「Django×Python」
という書籍を見る限りは普通のDjangoと手順に違いはなさそうです。

  1. アプリの作成
  2. Bookモデルの作成
  3. リスト表示のview/templateの作成
  4. URLとviewの紐付け

一つずつ処理して行きます。

  1. アプリの作成
    manage.pyスクリプトで行います。ココではbooklistという名前のアプリケーションを作成しました。

    $ ./manage.py startapp booklist
    $ ls booklist
    -rw-r--r--  1 taichino  staff    0  8  5 23:46 __init__.py
    drwxr-xr-x  2 taichino  staff   68  8  5 23:46 media
    -rw-r--r--  1 taichino  staff  118  8  5 23:46 models.py
    drwxr-xr-x  2 taichino  staff   68  8  5 23:46 templates
    -rw-r--r--  1 taichino  staff  171  8  5 23:46 views.py
    

    これで、myproject直下にbooklistディレクトリが作成されます。またその中に幾つかファイルが作成されます。さらに作成したアプリケーションをプロジェクトに登録します。

    settings.pyのINSTALLED_APPSにbooklistを追加します。これでアプリケーションの追加は完了しました。以下実装を進めて行きます。

  2. Bookモデルの作成
    Djangoではmodels.pyにモデルオブジェクトを記述するのが慣習のようですのでそれに習います。

    # -*- coding: utf-8 -*-
    from django.utils.translation import ugettext_lazy as _
    from google.appengine.ext import db
    
    class Book(db.Model):
      title = db.StringProperty(required=True)
      price = db.IntegerProperty()
    

    また、作成したモデルデータを管理インタフェースで扱う為に、登録する必要があります。登録処理はadmin.pyで行うのが慣習のようです。

    from django.contrib import admin
    from booklist.models import Book
    
    class BookAdmin(admin.ModelAdmin):
      list_display = ('title', 'price')
    
    admin.site.register(Book)
    

    これでBookオブジェクトが作成され、管理インタフェースから扱う事が出来るようになります。幾つか登録しておきます。ここで登録したデータをアプリから表示します。

  3. リスト表示用のviewとtemplateの作成

    リストの表示処理をviews.pyに、受け皿になるテンプレートをbook_list.htmlに
    記述します。面倒なのでviews.pyではgeneric viewを使いました。

    views.py

    # -*- coding: utf-8 -*-
    from django.http import HttpResponseRedirect
    from django.utils.translation import ugettext as _
    from ragendja.template import render_to_response
    
    from django.views.generic.list_detail import object_list
    from booklist.models import Book
    
    def list(request):
      return object_list(request, Book.all())
    

    book_list.html

    
      
         

    Book listing

      {% for book in object_list %}
    • {{ book.title }} {{ book.price }}
    • {% endfor %}
  4. URLとviewの紐付け
    最後に3で作成したviews.pyのlistとurlを紐付けます。urlの紐付けはアプリへの紐付けと個々のビューへの紐付けの2段階で行うのが慣習のようですので、それに従います。

    まずmyproject/urls.pyでアプリをurlへ紐付けます。ここではbooklist/(.*)というurlに対してbooklist/urls.pyで紐付けを行うようにしました。myproject/urls.pyに以下の修正を行います。

    # -*- coding: utf-8 -*-
    from django.conf.urls.defaults import *
    from django.contrib import admin
    
    admin.autodiscover()
    
    urlpatterns = patterns('',
        ('^admin/(.*)', admin.site.root),
        (r'^booklist/', include('booklist.urls')),   # この行を追加
        (r'^$', 'django.views.generic.simple.direct_to_template', {'template': 'index.html'}),
    )
    

    次にbooklist/(action)のactionをviews.py内のメソッドに紐付けます。ここではlistに対してlistメソッドを紐付けています。

    from django.conf.urls.defaults import *
    
    urlpatterns = patterns(
        'booklist.views',
         (r'^list', 'list'),
    )
    

    http://localhost:8000/booklist/listにアクセスしてみます。先ほど登録したデータが無事に表示されましたね!

5. 本番サーバにアップロード
appcfg.pyは使いません。やはりmanage.pyを使います。以下でアップロードされます。

./manage.py update

なおアップロード完了後は、./manage.py shell –remoteでリモートサーバに対してシェルを打てますので、3と同様にユーザを作成できます。アップロード時に注意したいのは、app.yamlに記述しているアプリのバージョンです。GAE上で登録されていないバージョンを指定すると404のHTTP Errorがでます。僕は1つテスト用のアプリを登録しているのですが、色々なテストを行っているので、幾つもバージョンを入れ替えて使っています。今回新しいテストなので、新しいバージョンを指定してアップロードしようとしたのですが、上記のエラーでハマってしまいました。

以上、ざっとapp-engine-patch経由でDjangoを使ってみました。感想としてはmanage.pyのshell機能が特に強力でこれだけでも使う価値があると感じました。Djangoはまだ使い慣れていませんが、整然と整備されている印象でwebappで無理矢理作って行くよりもメンテナンスし易いアプリケーションが作れそうです。

参考文献は、GAEには対応してないですが、「Django×Python」が解り易くて良かったです。

Leave a Reply

Your email address will not be published. Required fields are marked *