Django1.5からdjango.contrib.authのユーザーモデル(User)を差し替えることが可能になっているが、この機能を実現しているのがMetaサブクラスのswappableオプション。
このオプションを使うと、settingsの設定でモデルクラスを差し替える機能をアプリケーションで提供できる。
差し替えを行うと、差し替え前のモデルはsyncdbの対象からも外れる。
試したバージョンはDjango1.6、Python3.3。
注意点
swappableオプションはプライベートAPIなので、今後Djangoのバージョンアップで予告なく変更、削除される可能性がある。
ドキュメントにはこの機能について意図的に書いてないみたい。
#19103 (Docs for swappable model option) – Django
アプリケーションコードでこの機能を使うことは推奨しない。
サンプルコード
ベースとなるアプリケーション(baseapp)では、抽象モデルであるAbstractItemクラスを用意し、その実装をItemクラスとする。
Itemクラスは差し替え可能として、別のアプリケーション(customapp)でCustomItemモデルを作成してそれに差し替えてみる。
baseapp/models.py
Metaのswappableには、settingsファイルの変数名を指定する。この例では、settings.BASEAPP_ITEM_MODELで差し替えるモデルクラスを指定する。
また、直接モデルクラスを使用できないので、モデルクラスを取得するためのget_item_model関数を作成している。
from django.db import models class AbstractItem(models.Model): """抽象モデル """ name = models.CharField(max_length=100) class Meta: abstract = True class Item(AbstractItem): """syncdb対象となるモデル 差し替え可能とする """ class Meta(AbstractItem.Meta): swappable = 'BASEAPP_ITEM_MODEL' db_table = 'item' def display(self): return self.name def get_item_model(): """Itemモデルクラスを取得する関数 """ from django.conf import settings app_label, model_name = settings.BASEAPP_ITEM_MODEL.split('.') item_model = models.get_model(app_label, model_name) return item_model def print_all_items(): """Itemモデルのデータを取得して画面に表示する関数 """ item_model = get_item_model() for item in item_model.objects.all(): print(item.display())
customapp/models.py
from django.db import models from baseapp.models import AbstractItem class CustomItem(AbstractItem): """カスタマイズしたモデル """ price = models.IntegerField() class Meta(AbstractItem.Meta): db_table = 'custom_item' def display(self): return "{}: {}".format(self.name, self.price)
swappable_model_proj/settings.py(抜粋)
差し替えるモデルクラスの指定は、 app_label.Model の形式となる。
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'baseapp', 'customapp', ) BASEAPP_ITEM_MODEL = 'customapp.CustomItem'
customapp/admin.py
管理画面へ登録する際はCustomItemを登録する。baseapp/admin.pyでItemモデルを登録するように書かれていても、そちらは登録されない。
from django.contrib import admin from .models import CustomItem admin.site.register(CustomItem)
実行結果
管理画面からCustomItemのデータを追加して、shellからprint_all_items関数を実行した結果。
>>> from baseapp import models >>> models.print_all_items() spam: 200 ham: 150 egg: 100 >>> models.get_item_model() <class 'customapp.models.CustomItem'>