Engineer in Tokyo

Django 1.2 の変更のまとめ

先週、 Django 1.2 が出ました。新しくて、良い機能がいっぱい入っているけども、1.1 からの変更をご紹介しようかと思っています。

マルチDB

1.2 では、一番大きい変更は明らかに マルチDB対応 ですね。 settings.pyDATABASE オプションは DATABASES になりました。それで python 辞書で複数のDBを設定する。

以下のように MySQL、sqlite、PostgreSQL、それぞれ違ってても構いません。

DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'users': {
        'NAME': 'user_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'priv4te'
    }
}

どのデータベースをどの場合に使うかをデータベースルータで決める。 モデルの読み込みの場合のDB、書き込みの場合のDB、リレーションを許可するかどうか、syncdb (テーブル定義)の許可を実装する。

class MyAppRouter(object):
    """myappアプリケーションのモデルを別DBに保存し、
    DBの操作を制御する"""

    def db_for_read(self, model, **hints):
        "'myapp'の場合、'other'というDBを使う。"
        if model._meta.app_label == 'myapp':
            return 'other'
        return None

    def db_for_write(self, model, **hints):
        "'myapp'の場合、'other'というDBを使う。"
        if model._meta.app_label == 'myapp':
            return 'other'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        "両方のモデルが'myapp'に入っている場合のみにリレーションを許可"
        if obj1._meta.app_label == 'myapp' or obj2._meta.app_label == 'myapp':
            return True
        return None

    def allow_syncdb(self, db, model):
        "'myapp''other' DB のみに入れるようにする。"
        if db == 'other':
            return model._meta.app_label == 'myapp'
        elif model._meta.app_label == 'myapp':
            return False
        return None

モデル検証

モデルのデータを検証すること ができるようになりました。それに、新しいモジュール django.core.validators ができました。

フォームと同じように full_clean(), clean_fields(), clean(), validate_unique() の 4つのメソッドが追加されました。

clean_fields(exclude=None) を呼び出すとモデルのフィールドのデータを一個一個検証する。

clean() はカスタム検証の処理を実装するためのメソッド。このメソッドをサブクラスで実装すれば、カスタム検証ができます。

validate_unique(exclude=None) はユニークフィールドの検証を行う。

full_clean(exclude=None) を呼び出すとすべての検証を行います。

exclude パラメーターで検証を行わないフィールドを指定できる。

CSRF 対策

1.1の CsrfMiddleware は正規表現でCSRF用フィールドをフォームに突っ込むことができたが、実装が微妙でJSなどに使えなかったので、Django 1.2でもっと綺麗なAPIが揃えました

django.middleware.csrf.CsrfViewMiddleware が新しくできました。 このミードールウエアでCSRFのトーケンが生成され、ポストの場合、検証が行われ {% csrf_token %} テンプレートタグでフォームに入れることができている。

Middleware を使いたくない場合は、 CSRF対策をしたい viewのみに django.views.decorators.csrf.csrf_protect デコレータを使うことができます。

messages API

以前、Djangoのユーザメッセージは 「変更しました」とか、「削除しました」とか、一時的なメッセージなのに DB に保存しましたので、微妙だった。

それで、Django 1.2 では新しい messages API ができました。 DB のかわりにセキュアクッキーとセッションを使えるようになりました。後、メッセージタイプ、info、warning、errorなどが使えるようになりました。

from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')
messages.success(request, u'プロフィールを更新しました。')
messages.warning(request, u'サービス契約が後3日で切ります。')
messages.error(request, u'レコードが削除されました')

メールバックエンド

クラウドサービスでは、メールがAPI で提供されているのが多くて、Django 1.1 では send_mail は使えなかったんですけど、 Django 1.2では メールバックエンド が使えるようになりました。

標準に入っているのは、SMTP、コンソールに出力するのみ、メールを無視するバックエンドが揃えている。

カスタムバックエンドを作るために、 django.core.mail.backends.base.BaseEmailBackend を継承して、 send_messages(email_messages) を実装する。 永続コネクションを使う時は open()close() メソッドを実装すれば良い。

smart if テンプレートタグ

Django 1.1 以前では、 if テンプレートタグは boolean しか使えなくて、複雑なコンディションが書けなかった。 Django 1.2 から、 ==><andor などが使えれるようになりました。

{% if a != b %}
    ...
    {% if c == d and e >= f %}
    ...
    {% endif %}
 ...
{% endif %}

まとめ

ちょっとしたバグのため、Django 1.2.1 がすぐ出ると思いますが、Django 1.2 は良い新規機能が多くて、是非使って見てください。