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のユーザメッセージは「変更しました」とか、「削除しました」とか、一時的なメッセージなのにデータベースに保存しましたので、微妙だった。

それで、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は良い新規機能が多くて、是非使って見てください。