複数のデータベース¶
ここでは、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
で、現在進行中の読み取りまたは書き込み操作に関連するオブジェクトのインスタンスです。これは保存されるインスタンスかもしれませんし、多対多の関係で追加されるインスタンスかもしれません。場合によっては、インスタンスヒントは全く提供されません。ルーターはインスタンスヒントの存在をチェックし、そのヒントを使用してルーティング動作を変更すべきかどうかを決定します。
ルーターを使用する¶
データベースルーターは 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
# 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やサードパーティアプリにも同じアプローチを使用してください。
警告
コンテンツ・タイプを複数のデータベースに同期する場合、データベース間でプライマリ・キーが一致しない可能性があることに注意してください。その結果、データが破損したり、データが失われたりする可能性があります。