複数のデータベース¶
ここでは、Djangoがサポートする複数データベースの扱いについて説明します。残りのDjangoのドキュメントの大部分は、あなたが一つのデータベース扱うことを前提としています。複数のデータベースを使いたいなら、いくつかの追加ステップを踏む必要があります。
参考
複数のデータベースを使用したテストに付いての情報は、マルチデータベースのサポート を参照してください。
データベースを定義する¶
Django でデータベースを使う最初のステップは、利用するデータベースサーバーを Django に教えることです。これは、DATABASES の設定で行います。この設定は、データベースへのエイリアスです。Django を通してデータベースを参照するためのデータベースエイリアスを、辞書にマッピングします。この辞書の設定の詳細は、DATABASES ドキュメントで説明しています。
データベースには、選択した任意のエイリアスを付けることができます。しかし、エイリアス default は特別な意味があります。Django は、他のデータベースが選択されていない場合、default というエイリアスを持つデータベースを使用します。
以下に示すのは、2つのデータベース、すなわちデフォルトの PostgreSQL データベースと users という名前の MySQL データベースを定義した settings.py スニペットの例です。
DATABASES = {
"default": {
"NAME": "app_data",
"ENGINE": "django.db.backends.postgresql",
"USER": "postgres_user",
"PASSWORD": "s3krit",
},
"users": {
"NAME": "user_data",
"ENGINE": "django.db.backends.mysql",
"USER": "mysql_user",
"PASSWORD": "priv4te",
},
}
default データベースという概念がプロジェクトのコンテキストで意味をなさない場合、使用したいデータベースを注意深く常に指定する必要があります。Django は default データベースエントリーが定義されていることを要求しますが、使用しない場合はパラメータのディクショナリを空白のままにできます。これを行うには、使用している contrib とサードパーティを含むすべてのアプリのモデルで DATABASE_ROUTERS をセットアップしなければなりません。以下は、default エントリーを意図的に空のままにして、2つの default ではないデータベースを定義している settings.py スニペットの例です。
DATABASES = {
"default": {},
"users": {
"NAME": "user_data",
"ENGINE": "django.db.backends.mysql",
"USER": "mysql_user",
"PASSWORD": "superS3cret",
},
"customers": {
"NAME": "customer_data",
"ENGINE": "django.db.backends.mysql",
"USER": "mysql_cust",
"PASSWORD": "veryPriv@ate",
},
}
DATABASES 設定で定義されていないデータベースへのアクセスを試みた場合、Django は django.utils.connection.ConnectionDoesNotExist 例外を発生されます。
データベースを同期する¶
migrate 管理コマンドは一度に一つのデータベースに対して動作します。デフォルトでは default データベース上で動作しますが、 --database オプションを指定することで、別のデータベースを同期させることができます。つまり、上記の最初の例ですべてのモデルをすべてのデータベースに同期させるには、次のように呼び出します:
$ ./manage.py migrate
$ ./manage.py migrate --database=users
すべてのアプリケーションを特定のデータベースに同期させたくない場合には、特定のモデルの利用を制限するポリシーを実装した データベース ルーター を定義できます。
上記の2番目の例のように、 default データベースを空のままにしている場合、 migrate を実行するときは毎回データベース名を指定する必要があります。データベース名を省略するとエラーになります。2番目の例では次のようになります:
$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=customers
他の管理コマンドを使用する¶
データベースとやり取りする他のほとんどの django-admin コマンドは migrate と同じ方法で動作します ― これらは一度に一つのデータベース上でのみ動作し、使用するデータベースを制御するために --database を使用します。
このルールの例外は makemigrations コマンドです。このコマンドは新しいマイグレーションを作成する前に、データベース内のマイグレーション履歴を検証して、既存のマイグレーションファイルの問題 (マイグレーションファイル自体の編集によって起こるものを含む) を検出します。デフォルトでは default データベースのみをチェックしますが、 routers がインストールされている場合には allow_migrate() メソッドを参照します。
自動的なデータベースのルーティング¶
複数のデータベースを使用する最も簡単な方法は、データベースのルーティングスキームを設定することです。デフォルトのルーティングスキームでは、オブジェクトは元のデータベースに ''くっついた'' まま保存されます (つまり、foo データベースから取得したオブジェクトは同じデータベースに保存されます)。デフォルトのルーティングスキームでは、データベースが指定されていない場合、すべてのクエリは default データベースにフォールバックします。
デフォルトのルーティングスキームを有効にするために何もする必要はありません -- すべての Django プロジェクトで「箱から出してすぐに」使えます。しかし、もっと面白いデータベース割り当ての動作を実装したければ、独自の データベース ルーターを定義してインストールできます。
データベース ルーター¶
データベース ルーターは、以下の 4 つのメソッドを提供するクラスです:
- db_for_read(model, **hints)¶
model型のオブジェクトの読み取り操作に使用するデータベースをサジェストします。データベース操作がデータベースを選択する際に役立つ追加情報を提供できる場合、それは
hints辞書で与えられます。有効なヒントの詳細は 下記 を参照してください。サジェストがない場合は
Noneを返します。
- db_for_write(model, **hints)¶
Model型のオブジェクトの書き込みに使用するデータベースをサジェストします。
データベース操作がデータベースを選択する際に役立つ追加情報を提供できる場合、それは
hints辞書で与えられます。有効なヒントの詳細は 下記 を参照してください。サジェストがない場合は
Noneを返します。
- allow_relation(obj1, obj2, **hints)¶
もし
obj1とobj2の間のリレーションが許可されるべきであればTrueを、禁止されるべきであればFalseを、ルーターの意見がなければNoneを返します。これは純粋に検証操作であり、外部キーや多対多の操作で、2つのオブジェクト間でリレーションが許可されるべきかどうかを判断するために使用されます。どのルーターも意見を持たない場合 (つまり、すべてのルーターが
Noneを返す場合)、同じデータベース内のリレーションだけが許可されます。
- allow_migrate(db, app_label, model_name=None, **hints)¶
エイリアス
dbを持つデータベース上でマイグレーション操作を実行できるかどうかを判定します。操作を実行すべき場合はTrueを、実行すべきでない場合はFalseを、ルーターが意見を持たない場合はNoneを返します。位置引数
app_labelはマイグレーションするアプリケーションのラベルです。model_nameはマイグレーションするモデルのmodel._meta.model_name(モデルの__name__を小文字にしたもの) に設定されます。この値はRunPythonとRunSQL操作ではヒントを使用しない限りNoneです。hintsは特定の操作でルーターに追加情報を伝えるために使われます。model_nameがセットされている場合、通常hintsには'model'というキーの下にモデルクラスが含まれます。これは 履歴上のモデル であり、カスタム属性、メソッド、マネージャを持たないことに注意してください。_metaにのみ依存する必要があります。この方法は、指定されたデータベース上のモデルの可用性を判断するためにも使用できます。
makemigrationsは常にモデルの変更に対してマイグレーションを作成しますが、allow_migrate()がFalseを返した場合、dbでmigrateを実行すると、model_nameに対するマイグレーション操作はすべて警告なしにスキップされます。マイグレーションしているモデルに対してallow_migrate()の動作を変更すると、外部キーが壊れたり、テーブルが増えたり、テーブルがなくなったりする可能性があります。makemigrationsがマイグレーション履歴を確認するとき、マイグレーションが許可されていないデータベースはスキップされます。
ルーターはこれらのメソッドを 全て 提供する必要はありません -- 1 つ以上省略してもかまいません。もしメソッドの1つが省略された場合、 Django は関連するチェックを行う際にそのルーターをスキップします。
ヒント¶
データベースルーターが受け取ったヒントは、与えられたリクエストをどのデータベースが受け取るべきかを決定するために使うことができます。
現在のところ、提供される唯一のヒントは instance で、現在進行中の読み取りまたは書き込み操作に関連するオブジェクトのインスタンスです。これは保存されるインスタンスかもしれませんし、多対多の関係で追加されるインスタンスかもしれません。場合によっては、インスタンスヒントは全く提供されません。ルーターはインスタンスヒントの存在をチェックし、そのヒントを使用してルーティング動作を変更すべきかどうかを決定します。
If an instance hint is present, the database from which it was fetched
is recorded on its instance._state.db.
Routers will need to first consult that attribute before falling back to any
fixed alias to match Django's default behavior of fetching related instances
from the same database.
ルーターを使用する¶
データベースルーターは DATABASE_ROUTERS 設定を使ってインストールします。この設定はクラス名のリストを定義し、それぞれがベースルーター (django.db.router) が使用するルーターを指定します。
ベースルーターは Django のデータベース操作で、データベースの使用量を割り当てるために使われます。クエリがどのデータベースを使うか知る必要があれば常に、ベースルーターを呼び出し、 モデルとヒント (もしあれば) を提供します。ベースルーターは、データベースのサジェストを返すルーターが現れるまで、順番に各ルータークラスを試します。ヒントを返すルーターがない場合、ベースルーターはヒントインスタンスの instance._state.db を試します。ヒントインスタンスが提供されなかった場合、または instance._state.db が None の場合、ベースルーターは default データベースを割り当てます。
例¶
例としてのみ使用してください!
この例は、ルーターのインフラストラクチャを使用してデータベースの使用状況を変更する方法のデモを示すことだけを目的としています。ルーターの使用方法を紹介するために、いくつかの複雑な問題を意図的に無視しています。
この例は、myapp 内のモデルのいずれかに other データベースの外部にあるモデルとのリレーションが含まれている場合には機能しません。クロスデータベース リレーション を使うと、現時点では Django が処理できない参照整合性の問題が発生します。
プライマリ/レプリカ(一部のデータベースではマスター/スレーブと呼ばれる)構成も欠陥があります。レプリケーション・ラグ(書き込みがレプリカに伝搬するまでに時間がかかるために発生するクエリの不整合)を処理するソリューションを提供していません。また、トランザクションとデータベース利用戦略との相互作用も考慮されていません。
では、実際にはどうなのでしょうか?別のサンプル構成を考えてみましょう。1つは auth アプリケーション用で、他のアプリケーションはプライマリ/レプリカのセットアップを使用し、2つのリードレプリカを使用します。これらのデータベースを指定する設定は以下の通りです:
DATABASES = {
"default": {},
"auth_db": {
"NAME": "auth_db_name",
"ENGINE": "django.db.backends.mysql",
"USER": "mysql_user",
"PASSWORD": "swordfish",
},
"primary": {
"NAME": "primary_name",
"ENGINE": "django.db.backends.mysql",
"USER": "mysql_user",
"PASSWORD": "spam",
},
"replica1": {
"NAME": "replica1_name",
"ENGINE": "django.db.backends.mysql",
"USER": "mysql_user",
"PASSWORD": "eggs",
},
"replica2": {
"NAME": "replica2_name",
"ENGINE": "django.db.backends.mysql",
"USER": "mysql_user",
"PASSWORD": "bacon",
},
}
次に、ルーティングを処理する必要があります。まず、 auth と contenttypes アプリのクエリを auth_db に送信するルーターが必要です (auth モデルは ContentType にリンクされているので、同じデータベースに格納されている必要があります):
class AuthRouter:
"""
A router to control all database operations on models in the
auth and contenttypes applications.
"""
route_app_labels = {"auth", "contenttypes"}
def db_for_read(self, model, **hints):
"""
Attempts to read auth and contenttypes models go to auth_db.
"""
if model._meta.app_label in self.route_app_labels:
return "auth_db"
return None
def db_for_write(self, model, **hints):
"""
Attempts to write auth and contenttypes models go to auth_db.
"""
if model._meta.app_label in self.route_app_labels:
return "auth_db"
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the auth or contenttypes apps is
involved.
"""
if (
obj1._meta.app_label in self.route_app_labels
or obj2._meta.app_label in self.route_app_labels
):
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the auth and contenttypes apps only appear in the
'auth_db' database.
"""
if app_label in self.route_app_labels:
return db == "auth_db"
return None
また、他のすべてのアプリをプライマリ/レプリカ構成に送り、ランダムにレプリカを選んで読み込むルーターも必要です:
import random
class PrimaryReplicaRouter:
def db_for_read(self, model, **hints):
"""
Reads go to a randomly-chosen replica.
"""
return random.choice(["replica1", "replica2"])
def db_for_write(self, model, **hints):
"""
Writes always go to primary.
"""
return "primary"
def allow_relation(self, obj1, obj2, **hints):
"""
Relations between objects are allowed if both objects are
in the primary/replica pool.
"""
db_set = {"primary", "replica1", "replica2"}
if obj1._state.db in db_set and obj2._state.db in db_set:
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
All non-auth models end up in this pool.
"""
return True
最後に、設定ファイルに以下を追加します (path.to. はルーターが定義されているモジュールの実際のPythonパスで置き換えてください):
DATABASE_ROUTERS = ["path.to.AuthRouter", "path.to.PrimaryReplicaRouter"]
ルーターが処理される順番は重要です。ルーターは DATABASE_ROUTERS 設定にリストされている順番にクエリされます。この例では、 AuthRouter が PrimaryReplicaRouter よりも先に処理され、その結果、 auth のモデルに関する決定が他の決定よりも先に処理されます。もし DATABASE_ROUTERS 設定が2つのルーターを他の順番でリストしていた場合、 PrimaryReplicaRouter.allow_migrate() が最初に処理されます。PrimaryReplicaRouter実装のキャッチオール特性により、すべてのデータベースですべてのモデルが利用可能になります。
このセットアップをインストールし、 データベースを同期する に従って全てのデータベースをマイグレーションした状態で、Django のコードを実行してみましょう:
>>> # This retrieval will be performed on the 'auth_db' database
>>> fred = User.objects.get(username="fred")
>>> fred.first_name = "Frederick"
>>> # This save will also be directed to 'auth_db'
>>> fred.save()
>>> # These retrieval will be randomly allocated to a replica database
>>> dna = Person.objects.get(name="Douglas Adams")
>>> # A new object has no database allocation when created
>>> mh = Book(title="Mostly Harmless")
>>> # This assignment will consult the router, and set mh onto
>>> # the same database as the author object
>>> mh.author = dna
>>> # This save will force the 'mh' instance onto the primary database...
>>> mh.save()
>>> # ... but if we re-retrieve the object, it will come back on a replica
>>> mh = Book.objects.get(title="Mostly Harmless")
この例では auth アプリのモデルとのやりとりを処理するルーターと、その他のアプリとのやりとりを処理するルーターを定義しています。もし default データベースを空のままにしていて、他に指定されていないすべてのアプリを処理するためのデータベースルーターを定義したくない場合は、マイグレーションする前に INSTALLED_APPS にあるすべてのアプリの名前をルーターで処理する必要があります。1つのデータベースにまとめなければならないcontribアプリについては contribアプリの振る舞い を参照してください。
データベースを手動で選択する¶
Django は、コード中でデータベースの利用を完全に制御できる API も提供し ています。手動で指定したデータベースの割り当てが、データベースルーターが割り当てたデー タベースよりも優先されます。
QuerySet のためのデータベースを手動で選択する¶
QuerySet の "チェーン" のどの時点でも、 QuerySet のデータベースを選択できます。指定したデータベースを使用する別の QuerySet を取得するには、 QuerySet の using() を呼び出します。
using() は引数を1つ取り、クエリを実行したいデータベースのエイリアスを指定します。例えば次のようにします:
>>> # This will run on the 'default' database.
>>> Author.objects.all()
>>> # So will this.
>>> Author.objects.using("default")
>>> # This will run on the 'other' database.
>>> Author.objects.using("other")
save() のためのデータベースを選択する¶
データを保存するデータベースを指定するには Model.save() に using キーワードを使用します。
例えば、 legacy_users データベースにオブジェクトを保存するには、次のようにします:
>>> my_object.save(using="legacy_users")
もし using を指定しなければ、 save() メソッドはルーターが割り当てたデフォルトのデータベースに保存します。
オブジェクトを1つのデータベースからもう1つのデータベースに移動する¶
あるデータベースにインスタンスを保存した場合、インスタンスを新しいデータベースにマイグレーションする方法として save(using=...) を使いたくなるかもしれません。しかし、適切な手順を踏まないと、これは予期せぬ結果を招く可能性があります。
以下の例を考えてみてください。
>>> p = Person(name="Fred")
>>> p.save(using="first") # (statement 1)
>>> p.save(using="second") # (statement 2)
statement 1 では、新しい Person オブジェクトが first データベースに保存されます。この時、 p には主キーがないので、 Django は SQL の INSERT 文を発行します。これにより主キーが作成され、 Django はその主キーを p に割り当てます。
statement 2 で保存が行われるとき、 p はすでに主キーの値を持っていて、 Django は新しいデータベースでその主キーを使おうとします。もし主キーの値が second のデータベースで使われていなければ、何の問題もありません -- オブジェクトは新しいデータベースにコピーされます。
しかし、 p の主キーがすでに second データベースで使用されている場合は、 p が保存されたときに second データベースの既存のオブジェクトが上書きされます。
これを回避するには2つの方法があります。1つ目の方法は、インスタンスの主キーをクリアすることです。オブジェクトに主キーがない場合、 Django はそのオブジェクトを新しいオブジェクトとして扱い、 second データベースのデータが失われるのを防ぎます:
>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.pk = None # Clear the primary key.
>>> p.save(using="second") # Write a completely new object.
2 つ目のオプションは、 save() に force_insert オプションをつけて、 Django が SQL の INSERT を行うようにすることです:
>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.save(using="second", force_insert=True)
これにより、 Fred という人物は両方のデータベースで同じ主キーを持つことになります。もしその主キーがすでに second データベースで使用されている場合、保存しようとするとエラーが発生します。
削除が行われるデータベースを選択する¶
デフォルトでは、既存のオブジェクトを削除する呼び出しは、最初にオブジェクトを取得するために使用したのと同じデータベース上で実行されます。
>>> u = User.objects.using("legacy_users").get(username="fred")
>>> u.delete() # will delete from the `legacy_users` database
モデルを削除するデータベースを指定するには、using キーワード引数を Model.delete() メソッドに渡します。この引数は、save() の using キーワード引数と同じように機能します。
例えば、あるユーザーを legacy_users データベースから new_users データベースにマイグレーションする場合、以下のコマンドを使用します:
>>> user_obj.save(using="new_users")
>>> user_obj.delete(using="legacy_users")
複数のデータベースでマネージャを使う¶
デフォルト以外のデータベースにマネージャがアクセスできるようにするには、マネージャの db_manager() メソッドを使用します。
例えば、データベースにアクセスするカスタムマネージャメソッド User.objects.create_user() があるとします。 create_user() はマネージャメソッドであり、 QuerySet メソッドではないので、 User.objects.using('new_users').create_user() は実行できません。 (create_user() メソッドはマネージャである User.objects でのみ使用可能で、マネージャから派生した QuerySet オブジェクトでは使用できません)。解決策は、次のように db_manager() を使うことです:
User.objects.db_manager("new_users").create_user(...)
db_manager() は指定したデータベースに結び付けられたマネージャのコピーを返します。
複数のデータベースで get_queryset() を使う¶
マネージャ上で get_queryset() をオーバーライドする場合は、親メソッドを呼び出す (super() を使用する) か、マネージャの _db 属性 (使用するデータベースの名前を含む文字列) を適切に処理するようにしてください。
例えば、カスタム QuerySet クラスを get_queryset メソッドから返したい場合は、このようにします:
class MyManager(models.Manager):
def get_queryset(self):
qs = CustomQuerySet(self.model)
if self._db is not None:
qs = qs.using(self._db)
return qs
Django の管理インタフェースで複数のデータベースを公開する¶
Django の admin は複数のデータベースを明示的にサポートしていません。ルーターチェーンで指定したデータベース以外のデータベース上のモデルに対して admin インタフェースを提供したい場合は、 admin が特定のデータベースをコンテンツに使うように指示するカスタム ModelAdmin クラスを書く必要があります。
ModelAdmin オブジェクトには、複数のデータベースのサポートのためのカスタマイズが必要な以下のメソッドがあります:
class MultiDBModelAdmin(admin.ModelAdmin):
# A handy constant for the name of the alternate database.
using = "other"
def save_model(self, request, obj, form, change):
# Tell Django to save objects to the 'other' database.
obj.save(using=self.using)
def delete_model(self, request, obj):
# Tell Django to delete objects from the 'other' database
obj.delete(using=self.using)
def get_queryset(self, request):
# Tell Django to look for objects on the 'other' database.
return super().get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
# Tell Django to populate ForeignKey widgets using a query
# on the 'other' database.
return super().formfield_for_foreignkey(
db_field, request, using=self.using, **kwargs
)
def formfield_for_manytomany(self, db_field, request, **kwargs):
# Tell Django to populate ManyToMany widgets using a query
# on the 'other' database.
return super().formfield_for_manytomany(
db_field, request, using=self.using, **kwargs
)
ここで示した実装はマルチデータベース戦略を実装したもので、指定されたタイプのオブジェクトはすべて特定のデータベースに保存されます (例えば、すべての User オブジェクトは other データベースに保存されます)。複数のデータベースをより複雑に使用する場合は、 ModelAdmin にその戦略を反映させる必要があります。
InlineModelAdmin オブジェクトも同じように扱うことができます。これらのオブジェクトには3つのカスタマイズされたメソッドが必要です:
class MultiDBTabularInline(admin.TabularInline):
using = "other"
def get_queryset(self, request):
# Tell Django to look for inline objects on the 'other' database.
return super().get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
# Tell Django to populate ForeignKey widgets using a query
# on the 'other' database.
return super().formfield_for_foreignkey(
db_field, request, using=self.using, **kwargs
)
def formfield_for_manytomany(self, db_field, request, **kwargs):
# Tell Django to populate ManyToMany widgets using a query
# on the 'other' database.
return super().formfield_for_manytomany(
db_field, request, using=self.using, **kwargs
)
モデル管理定義を書いたら、任意の Admin インスタンスに登録できます:
from django.contrib import admin
from myapp.models import Author, Book, Publisher
# Import our custom ModelAdmin and TabularInline from where they're defined.
from myproject.admin import MultiDBModelAdmin, MultiDBTabularInline
# Specialize the multi-db admin objects for use with specific models.
class BookInline(MultiDBTabularInline):
model = Book
class PublisherAdmin(MultiDBModelAdmin):
inlines = [BookInline]
admin.site.register(Author, MultiDBModelAdmin)
admin.site.register(Publisher, PublisherAdmin)
othersite = admin.AdminSite("othersite")
othersite.register(Publisher, MultiDBModelAdmin)
この例では2つの管理サイトを設定しています。最初のサイトでは Author と Publisher オブジェクトが公開され、 Publisher オブジェクトにはその出版社が出版した書籍を示すインラインが表形式で表示されます。2番目のサイトでは、インラインを使わずに出版社だけを公開しています。
複数のデータベースで生のカーソルを使う¶
複数のデータベースを使用している場合、 django.db.connections を使用することで、特定のデータベースのコネクション (とカーソル) を取得できます。 django.db.connections は辞書のようなオブジェクトで、次のように、エイリアスを使って個別の接続を取得できます。
from django.db import connections
with connections["my_db_alias"].cursor() as cursor:
...
複数データベースの制約¶
データベースをまたぐリレーション¶
Djangoは現在、複数のデータベースにまたがる外部キーまたは多対多の関係をサポートしていません。もしモデルを異なるデータベースに分割するためにルーターを使用している場合、それらのモデルによって定義される外部キーおよび多対多の関係は、単一のデータベース内部に限定されなければなりません。
これは参照整合性のためです。2つのオブジェクト間のリレーションシップを維持するためには、Djangoはリレーション先オブジェクトの主キーが有効であることを知る必要があります。主キーが別のデータベースに格納されている場合、主キーが有効かどうかを判断するのは容易ではありません。
Postgres、SQLite、Oracle、MySQLをInnoDBで使用している場合、これはデータベースの整合性レベルで強制されます。データベースレベルのキー制約は、検証できないリレーションの作成を防ぎます。
しかし、MySQL で MyISAM テーブルを使用している場合、参照整合性は強制されません。その結果、データベースの外部キーを「偽装」できるかもしれません。しかし、この設定は Django では公式にはサポートされていません。
contribアプリの振る舞い¶
いくつかのcontribアプリはモデルを含み、いくつかのアプリは他のアプリに依存しています。データベースをまたいだリレーションシップは不可能であるため、データベースをまたいでこれらのモデルを分割する方法に制限が生じます:
contenttypes.ContentType,sessions.Session,sites.Siteはいずれも、適切なルーターがあれば、どのデータベースにも格納できます。User、Group、PermissionのauthモデルはContentTypeとリンクしているため、ContentTypeと同じデータベースに保存する必要があります。adminはauthに依存しているので、そのモデルはauthと同じデータベースに置く必要があります。flatpagesとredirectsはsitesに依存しているため、それらのモデルはsitesと同じデータベースに置く必要があります。
さらに、下記のようないくつかのオブジェクトは migrate がデータベースにテーブルを作成した直後に自動的に作成されます:
デフォルトの
Site、各モデル (そのデータベースに保存されていないものも含む) の
ContentType、各モデル(そのデータベースに保存されていないものも含む)の
Permission。
複数のデータベースを使用する通常のセットアップでは、これらのオブジェクトを複数のデータベースに持つことは有益ではありません。通常のセットアップには、プライマリ/レプリカや外部データベースへの接続などがあります。そのため、これら3つのモデルを1つのデータベースだけに同期させることができる データベースルーター を書くことを推奨します。複数のデータベースのテーブルを必要としないcontribやサードパーティアプリにも同じアプローチを使用してください。
警告
コンテンツ・タイプを複数のデータベースに同期する場合、データベース間でプライマリ・キーが一致しない可能性があることに注意してください。その結果、データが破損したり、データが失われたりする可能性があります。