複数のデータベース—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/topics/db/multi-db
移動先:案内検索

複数のデータベース

このトピックガイドでは、複数のデータベースと対話するためのDjangoのサポートについて説明します。 Djangoの残りのドキュメントのほとんどは、単一のデータベースを操作していることを前提としています。 複数のデータベースを操作する場合は、いくつかの追加手順を実行する必要があります。

も参照してください

複数のデータベースでのテストについては、マルチデータベースサポートを参照してください。


データベースの定義

Djangoで複数のデータベースを使用するための最初のステップは、使用するデータベースサーバーについてDjangoに通知することです。 これは、:setting: `DATABASES` 設定を使用して行われます。 この設定は、Django全体で特定のデータベースを参照する方法であるデータベースエイリアスを、その特定の接続の設定のディクショナリにマップします。 内部辞書の設定については、:setting: `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データベースエントリを定義する必要がありますが、パラメータディクショナリを使用しない場合は空白のままにすることができます。 これを行うには、使用しているコントリビュートアプリやサードパーティアプリのモデルを含む、すべてのアプリのモデルに対して:setting: `DATABASE_ROUTERS` を設定して、クエリがにルーティングされないようにする必要があります。デフォルトのデータベース。 以下は、2つのデフォルト以外のデータベースを定義するsettings.pyスニペットの例であり、defaultエントリは意図的に空のままになっています。

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'
    }
}

:setting: `DATABASES` 設定で定義していないデータベースにアクセスしようとすると、Djangoはdjango.utils.connection.ConnectionDoesNotExist例外を発生させます。


データベースの同期

:djadmin: `migrate` 管理コマンドは、一度に1つのデータベースで動作します。 デフォルトでは、defaultデータベースで動作しますが、--databaseオプションを指定することで、別のデータベースを同期するように指示できます。 したがって、上記の最初の例ですべてのモデルをすべてのデータベースに同期するには、次のコマンドを呼び出す必要があります。

$ ./manage.py migrate
$ ./manage.py migrate --database=users

すべてのアプリケーションを特定のデータベースに同期させたくない場合は、特定のモデルの可用性を制限するポリシーを実装するデータベースルーターを定義できます。

上記の2番目の例のように、defaultデータベースを空のままにした場合は、:djadmin: `migrate` を実行するたびにデータベース名を指定する必要があります。 データベース名を省略すると、エラーが発生します。 2番目の例の場合:

$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=customers

他の管理コマンドの使用

データベースと対話する他のほとんどのdjango-adminコマンドは、:djadmin: `migrate` と同じように動作します。これらは、--databaseを使用して、一度に1つのデータベースでのみ動作します。 ]使用するデータベースを制御します。

このルールの例外は、:djadmin: `makemigrations` コマンドです。 データベース内の移行履歴を検証して、新しい移行を作成する前に、既存の移行ファイルの問題(編集によって発生する可能性があります)を検出します。 デフォルトでは、defaultデータベースのみをチェックしますが、ルーターallow_migrate()メソッドがインストールされている場合はそれを参照します。


自動データベースルーティング

複数のデータベースを使用する最も簡単な方法は、データベースルーティングスキームを設定することです。 デフォルトのルーティングスキームにより、オブジェクトは元のデータベースに「固定」されたままになります(つまり、fooデータベースから取得されたオブジェクトは同じデータベースに保存されます)。 デフォルトのルーティングスキームでは、データベースが指定されていない場合、すべてのクエリがdefaultデータベースにフォールバックします。

デフォルトのルーティングスキームをアクティブにするために何もする必要はありません-それはすべてのDjangoプロジェクトで「箱から出して」提供されます。 ただし、より興味深いデータベース割り当て動作を実装する場合は、独自のデータベースルーターを定義してインストールできます。

データベースルーター

データベースルーターは、最大4つのメソッドを提供するクラスです。

db_for_read(model, **hints)

タイプmodelのオブジェクトの読み取り操作に使用する必要があるデータベースを提案します。

データベース操作でデータベースの選択に役立つ可能性のある追加情報を提供できる場合は、hintsディクショナリで提供されます。 有効なヒントの詳細は、以下に記載されています。

提案がない場合はNoneを返します。

db_for_write(model, **hints)

モデルタイプのオブジェクトの書き込みに使用するデータベースを提案します。

データベース操作でデータベースの選択に役立つ可能性のある追加情報を提供できる場合は、hintsディクショナリで提供されます。 有効なヒントの詳細は、以下に記載されています。

提案がない場合はNoneを返します。

allow_relation(obj1, obj2, **hints)

obj1obj2の間の関係を許可する必要がある場合は、Trueを返し、関係を防止する必要がある場合はFalseを返し、ルーターは意見がありません。 これは純粋に検証操作であり、外部キーと、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のみに依存する必要があります。

この方法は、特定のデータベースでのモデルの可用性を判断するためにも使用できます。

:djadmin: `makemigrations` は常にモデル変更の移行を作成しますが、allow_migrate()Falseを返す場合、model_nameの移行操作はすべてサイレントにスキップされますdb:djadmin: `migrate` を実行している場合。 すでに移行されているモデルのallow_migrate()の動作を変更すると、外部キーの破損、余分なテーブル、またはテーブルの欠落が発生する可能性があります。 :djadmin: `makemigrations` が移行履歴を確認するとき、アプリの移行が許可されていないデータベースをスキップします。

ルーターは、すべてのこれらのメソッドを提供する必要はありません。1つ以上のメソッドを省略できます。 いずれかの方法を省略した場合、Djangoは関連するチェックを実行するときにそのルーターをスキップします。

ヒント

データベースルーターが受信したヒントを使用して、特定の要求を受信するデータベースを決定できます。

現在、提供されるヒントはinstanceのみです。これは、進行中の読み取りまたは書き込み操作に関連するオブジェクトインスタンスです。 これは、保存されているインスタンスの場合もあれば、多対多の関係で追加されているインスタンスの場合もあります。 場合によっては、インスタンスのヒントがまったく提供されません。 ルータはインスタンスヒントの存在を確認し、そのヒントを使用してルーティング動作を変更する必要があるかどうかを判断します。


ルーターの使用

データベースルーターは、:setting: `DATABASE_ROUTERS` 設定を使用してインストールされます。 この設定は、クラス名のリストを定義し、それぞれがマスタールーター(django.db.router)によって使用されるルーターを指定します。

マスタールーターは、データベースの使用量を割り当てるためにDjangoのデータベース操作によって使用されます。 クエリが使用するデータベースを知る必要があるときはいつでも、マスタールーターを呼び出して、モデルとヒント(利用可能な場合)を提供します。 次に、Djangoは、データベースの提案が見つかるまで、各ルーターを順番に試行します。 提案が見つからない場合は、ヒントインスタンスの現在の instance._state.db を試行します。 ヒントインスタンスが提供されなかった場合、または instance._state.dbNoneの場合、マスタールーターは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

最後に、設定ファイルに以下を追加します(ルーターが定義されているモジュールへの実際のPythonパスをpath.to.に置き換えます)。

DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.PrimaryReplicaRouter']

ルーターが処理される順序は重要です。 ルーターは、:setting: `DATABASE_ROUTERS` 設定にリストされている順序で照会されます。 この例では、AuthRouterPrimaryReplicaRouterの前に処理されるため、authのモデルに関する決定は他の決定が行われる前に処理されます。 :setting: `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データベースを空のままにし、特に指定されていないすべてのアプリを処理するキャッチオールデータベースルーターを定義したくない場合、ルーターは:setting: `ですべてのアプリの名前を処理する必要があります。移行する前にINSTALLED_APPS` 。 1つのデータベースにまとめる必要があるcontribアプリについては、 contribappsの動作を参照してください。


データベースを手動で選択する

Djangoは、コード内のデータベースの使用を完全に制御できるAPIも提供します。 手動で指定されたデータベース割り当ては、ルーターによって割り当てられたデータベースよりも優先されます。

QuerySetのデータベースを手動で選択する

QuerySet「チェーン」の任意の時点でQuerySetのデータベースを選択できます。 QuerySetusing()を呼び出して、指定されたデータベースを使用する別のQuerySetを取得します。

using()は、クエリを実行するデータベースのエイリアスという1つの引数を取ります。 例えば:

>>> # This will run on the 'default' database.
>>> Author.objects.all()

>>> # So will this.
>>> Author.objects.using('default').all()

>>> # This will run on the 'other' database.
>>> Author.objects.using('other').all()

save()のデータベースを選択しています

usingキーワードをModel.save()に使用して、データを保存するデータベースを指定します。

たとえば、オブジェクトをlegacy_usersデータベースに保存するには、次を使用します。

>>> my_object.save(using='legacy_users')

usingを指定しない場合、save()メソッドはルーターによって割り当てられたデフォルトのデータベースに保存されます。

あるデータベースから別のデータベースへのオブジェクトの移動

インスタンスを1つのデータベースに保存した場合、インスタンスを新しいデータベースに移行する方法としてsave(using=...)を使用したくなるかもしれません。 ただし、適切な手順を実行しないと、予期しない結果が生じる可能性があります。

次の例を考えてみましょう。

>>> p = Person(name='Fred')
>>> p.save(using='first')  # (statement 1)
>>> p.save(using='second') # (statement 2)

ステートメント1では、新しいPersonオブジェクトがfirstデータベースに保存されます。 現時点では、pには主キーがないため、DjangoはSQL INSERTステートメントを発行します。 これにより主キーが作成され、Djangoはその主キーをpに割り当てます。

ステートメント2で保存が行われると、pにはすでに主キー値があり、Djangoは新しいデータベースでその主キーを使用しようとします。 主キー値がsecondデータベースで使用されていない場合、問題は発生しません。オブジェクトは新しいデータベースにコピーされます。

ただし、pの主キーがsecondデータベースですでに使用されている場合、pが保存しました。

これは2つの方法で回避できます。 まず、インスタンスの主キーをクリアできます。 オブジェクトに主キーがない場合、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番目のオプションは、force_insertオプションをsave()に使用して、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()メソッドは、マネージャーから派生したQuerySetオブジェクトではなく、マネージャーであるUser.objectsでのみ使用できます。)解決策は、db_manager()を使用することです。このような:

User.objects.db_manager('new_users').create_user(...)

db_manager()は、指定したデータベースにバインドされているマネージャーのコピーを返します。

複数のデータベースでget_queryset()を使用する

マネージャーでget_queryset()をオーバーライドする場合は、必ず親でメソッドを呼び出すか(super()を使用)、で_db属性を適切に処理してください。 manager(使用するデータベースの名前を含む文字列)。

たとえば、get_querysetメソッドからカスタム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の管理者は、複数のデータベースを明示的にサポートしていません。 ルーターチェーンで指定されたもの以外のデータベース上のモデルに管理インターフェイスを提供する場合は、コンテンツに特定のデータベースを使用するように管理者に指示するカスタム ModelAdmin クラスを作成する必要があります。 。

ModelAdminオブジェクトには、複数データベースをサポートするためのカスタマイズが必要な5つのメソッドがあります。

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は関連するオブジェクトの主キーが有効であることを知る必要があります。 主キーが別のデータベースに保存されている場合、主キーの有効性を簡単に評価することはできません。

InnoDBでPostgres、Oracle、またはMySQLを使用している場合、これはデータベースの整合性レベルで適用されます。データベースレベルのキー制約により、検証できない関係が作成されなくなります。

ただし、MyISAMテーブルでSQLiteまたはMySQLを使用している場合、強制的な参照整合性はありません。 その結果、クロスデータベースの外部キーを「偽造」できる可能性があります。 ただし、この構成はDjangoによって公式にサポートされていません。


contribアプリの動作

いくつかの投稿アプリにはモデルが含まれており、一部のアプリは他のアプリに依存しています。 データベース間の関係は不可能であるため、これらのモデルをデータベース間で分割する方法にいくつかの制限が生じます。

  • contenttypes.ContentTypesessions.Sessionsites.Siteのそれぞれは、適切なルーターがあれば、任意のデータベースに保存できます。
  • authモデル— UserGroupPermission —は互いにリンクされ、ContentTypeにリンクされているため、同じ場所に保管する必要がありますContentTypeとしてデータベース。
  • adminauthに依存しているため、そのモデルはauthと同じデータベースに存在する必要があります。
  • flatpagesredirectssitesに依存しているため、それらのモデルはsitesと同じデータベースに存在する必要があります。

さらに、一部のオブジェクトは、:djadmin: `migrate` がデータベースに保持するためのテーブルを作成した直後に、自動的に作成されます。

  • デフォルトのSite
  • 各モデル(そのデータベースに保存されていないモデルを含む)のContentType
  • 各モデルのPermission(そのデータベースに保存されていないモデルを含む)。

複数のデータベースを使用する一般的なセットアップでは、これらのオブジェクトを複数のデータベースに含めることは役に立ちません。 一般的なセットアップには、プライマリ/レプリカと外部データベースへの接続が含まれます。 したがって、これら3つのモデルを1つのデータベースにのみ同期できるデータベースルーターを作成することをお勧めします。 複数のデータベースにテーブルを配置する必要のないcontribアプリとサードパーティアプリにも同じアプローチを使用します。

警告

コンテンツタイプを複数のデータベースに同期する場合は、それらの主キーがデータベース間で一致しない可能性があることに注意してください。 これにより、データが破損したり、データが失われたりする可能性があります。