---
title: "複数のデータベース"
version: 5.2
locale: ja
source: https://docs.djangoproject.com/ja/5.2/topics/db/multi-db/
canonical: https://djangodocs.dev/ja/5.2/topics/db/multi-db/
---
# 複数のデータベース

ここでは、Djangoがサポートする複数データベースの扱いについて説明します。残りのDjangoのドキュメントの大部分は、あなたが一つのデータベース扱うことを前提としています。複数のデータベースを使いたいなら、いくつかの追加ステップを踏む必要があります。

> **See also**
>
> 複数のデータベースを使用したテストに付いての情報は、[マルチデータベースのサポート](/ja/5.2/topics/testing/tools/#testing-multi-db) を参照してください。

## データベースを定義する

Django でデータベースを使う最初のステップは、利用するデータベースサーバーを Django に教えることです。これは、[`DATABASES`](/ja/5.2/ref/settings/#std-setting-DATABASES) の設定で行います。この設定は、データベースへのエイリアスです。Django を通してデータベースを参照するためのデータベースエイリアスを、辞書にマッピングします。この辞書の設定の詳細は、[`DATABASES`](/ja/5.2/ref/settings/#std-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` データベースエントリーが定義されていることを要求しますが、使用しない場合はパラメータのディクショナリを空白のままにできます。これを行うには、使用している contrib とサードパーティを含むすべてのアプリのモデルで [`DATABASE_ROUTERS`](/ja/5.2/ref/settings/#std-setting-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`](/ja/5.2/ref/settings/#std-setting-DATABASES) 設定で定義されていないデータベースへのアクセスを試みた場合、Django は `django.utils.connection.ConnectionDoesNotExist` 例外を発生されます。

## データベースを同期する

[`migrate`](/ja/5.2/ref/django-admin/#django-admin-migrate) 管理コマンドは一度に一つのデータベースに対して動作します。デフォルトでは `default` データベース上で動作しますが、 [`--database`](/ja/5.2/ref/django-admin/#cmdoption-migrate-database) オプションを指定することで、別のデータベースを同期させることができます。つまり、上記の最初の例ですべてのモデルをすべてのデータベースに同期させるには、次のように呼び出します:

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

すべてのアプリケーションを特定のデータベースに同期させたくない場合には、特定のモデルの利用を制限するポリシーを実装した [データベース ルーター](#topics-db-multi-db-routing) を定義できます。

上記の2番目の例のように、 `default` データベースを空のままにしている場合、 [`migrate`](/ja/5.2/ref/django-admin/#django-admin-migrate) を実行するときは毎回データベース名を指定する必要があります。データベース名を省略するとエラーになります。2番目の例では次のようになります:

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

### 他の管理コマンドを使用する

データベースとやり取りする他のほとんどの `django-admin` コマンドは [`migrate`](/ja/5.2/ref/django-admin/#django-admin-migrate) と同じ方法で動作します ― これらは一度に一つのデータベース上でのみ動作し、使用するデータベースを制御するために `--database` を使用します。

このルールの例外は [`makemigrations`](/ja/5.2/ref/django-admin/#django-admin-makemigrations) コマンドです。このコマンドは新しいマイグレーションを作成する前に、データベース内のマイグレーション履歴を検証して、既存のマイグレーションファイルの問題 (マイグレーションファイル自体の編集によって起こるものを含む) を検出します。デフォルトでは `default` データベースのみをチェックしますが、 [routers](#topics-db-multi-db-routing) がインストールされている場合には [`allow_migrate()`](#allow_migrate) メソッドを参照します。

## 自動的なデータベースのルーティング

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

デフォルトのルーティングスキームを有効にするために何もする必要はありません -- すべての Django プロジェクトで「箱から出してすぐに」使えます。しかし、もっと面白いデータベース割り当ての動作を実装したければ、独自の データベース ルーターを定義してインストールできます。

### データベース ルーター

データベース ルーターは、以下の 4 つのメソッドを提供するクラスです:

#### `db_for_read(model, **hints)`

`model` 型のオブジェクトの読み取り操作に使用するデータベースをサジェストします。

データベース操作がデータベースを選択する際に役立つ追加情報を提供できる場合、それは `hints` 辞書で与えられます。有効なヒントの詳細は [下記](#topics-db-multi-db-hints) を参照してください。

サジェストがない場合は `None` を返します。

#### `db_for_write(model, **hints)`

Model型のオブジェクトの書き込みに使用するデータベースをサジェストします。

データベース操作がデータベースを選択する際に役立つ追加情報を提供できる場合、それは `hints` 辞書で与えられます。有効なヒントの詳細は [下記](#topics-db-multi-db-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`](/ja/5.2/ref/migration-operations/#django.db.migrations.operations.RunPython) と [`RunSQL`](/ja/5.2/ref/migration-operations/#django.db.migrations.operations.RunSQL) 操作ではヒントを使用しない限り `None` です。

`hints` は特定の操作でルーターに追加情報を伝えるために使われます。

`model_name` がセットされている場合、通常 `hints` には `'model'` というキーの下にモデルクラスが含まれます。これは [履歴上のモデル](/ja/5.2/topics/migrations/#historical-models) であり、カスタム属性、メソッド、マネージャを持たないことに注意してください。 `_meta` にのみ依存する必要があります。

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

[`makemigrations`](/ja/5.2/ref/django-admin/#django-admin-makemigrations) は常にモデルの変更に対してマイグレーションを作成しますが、 `allow_migrate()` が `False` を返した場合、 `db` で [`migrate`](/ja/5.2/ref/django-admin/#django-admin-migrate) を実行すると、 `model_name` に対するマイグレーション操作はすべて警告なしにスキップされます。マイグレーションしているモデルに対して `allow_migrate()` の動作を変更すると、外部キーが壊れたり、テーブルが増えたり、テーブルがなくなったりする可能性があります。 [`makemigrations`](/ja/5.2/ref/django-admin/#django-admin-makemigrations) がマイグレーション履歴を確認するとき、マイグレーションが許可されていないデータベースはスキップされます。

ルーターはこれらのメソッドを *全て* 提供する必要はありません -- 1 つ以上省略してもかまいません。もしメソッドの1つが省略された場合、 Django は関連するチェックを行う際にそのルーターをスキップします。

#### ヒント

データベースルーターが受け取ったヒントは、与えられたリクエストをどのデータベースが受け取るべきかを決定するために使うことができます。

現在のところ、提供される唯一のヒントは `instance` で、現在進行中の読み取りまたは書き込み操作に関連するオブジェクトのインスタンスです。これは保存されるインスタンスかもしれませんし、多対多の関係で追加されるインスタンスかもしれません。場合によっては、インスタンスヒントは全く提供されません。ルーターはインスタンスヒントの存在をチェックし、そのヒントを使用してルーティング動作を変更すべきかどうかを決定します。

### ルーターを使用する

データベースルーターは [`DATABASE_ROUTERS`](/ja/5.2/ref/settings/#std-setting-DATABASE_ROUTERS) 設定を使ってインストールします。この設定はクラス名のリストを定義し、それぞれがベースルーター (`django.db.router`) が使用するルーターを指定します。

ベースルーターは Django のデータベース操作で、データベースの使用量を割り当てるために使われます。クエリがどのデータベースを使うか知る必要があれば常に、ベースルーターを呼び出し、 モデルとヒント (もしあれば) を提供します。ベースルーターは、データベースのサジェストを返すルーターが現れるまで、順番に各ルータークラスを試します。ヒントを返すルーターがない場合、ベースルーターはヒントインスタンスの [`instance._state.db`](/ja/5.2/ref/models/instances/#django.db.models.Model._state) を試します。ヒントインスタンスが提供されなかった場合、または [`instance._state.db`](/ja/5.2/ref/models/instances/#django.db.models.Model._state) が `None` の場合、ベースルーターは `default` データベースを割り当てます。

### 例

> **例としてのみ使用してください！**
>
> この例は、ルーターのインフラストラクチャを使用してデータベースの使用状況を変更する方法のデモを示すことだけを目的としています。ルーターの使用方法を紹介するために、いくつかの複雑な問題を意図的に無視しています。
>
> この例は、`myapp` 内のモデルのいずれかに `other` データベースの外部にあるモデルとのリレーションが含まれている場合には機能しません。[クロスデータベース リレーション](#no-cross-database-relations) を使うと、現時点では 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`](/ja/5.2/ref/settings/#std-setting-DATABASE_ROUTERS) 設定にリストされている順番にクエリされます。この例では、 `AuthRouter` が `PrimaryReplicaRouter` よりも先に処理され、その結果、 `auth` のモデルに関する決定が他の決定よりも先に処理されます。もし [`DATABASE_ROUTERS`](/ja/5.2/ref/settings/#std-setting-DATABASE_ROUTERS) 設定が2つのルーターを他の順番でリストしていた場合、 `PrimaryReplicaRouter.allow_migrate()` が最初に処理されます。PrimaryReplicaRouter実装のキャッチオール特性により、すべてのデータベースですべてのモデルが利用可能になります。

このセットアップをインストールし、 [データベースを同期する](#synchronizing-multiple-databases) に従って全てのデータベースをマイグレーションした状態で、Django のコードを実行してみましょう:

```pycon
>>> # 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`](/ja/5.2/ref/settings/#std-setting-INSTALLED_APPS) にあるすべてのアプリの名前をルーターで処理する必要があります。1つのデータベースにまとめなければならないcontribアプリについては [contribアプリの振る舞い](#contrib-app-multiple-databases) を参照してください。

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

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

### `QuerySet` のためのデータベースを手動で選択する

`QuerySet` の "チェーン" のどの時点でも、 `QuerySet` のデータベースを選択できます。指定したデータベースを使用する別の `QuerySet` を取得するには、 `QuerySet` の `using()` を呼び出します。

`using()` は引数を1つ取り、クエリを実行したいデータベースのエイリアスを指定します。例えば次のようにします:

```pycon
>>> # 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` データベースにオブジェクトを保存するには、次のようにします:

```pycon
>>> my_object.save(using="legacy_users")
```

もし `using` を指定しなければ、 `save()` メソッドはルーターが割り当てたデフォルトのデータベースに保存します。

#### オブジェクトを1つのデータベースからもう1つのデータベースに移動する

あるデータベースにインスタンスを保存した場合、インスタンスを新しいデータベースにマイグレーションする方法として `save(using=...)` を使いたくなるかもしれません。しかし、適切な手順を踏まないと、これは予期せぬ結果を招く可能性があります。

以下の例を考えてみてください。

```pycon
>>> 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` データベースのデータが失われるのを防ぎます:

```pycon
>>> 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` を行うようにすることです:

```pycon
>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.save(using="second", force_insert=True)
```

これにより、 `Fred` という人物は両方のデータベースで同じ主キーを持つことになります。もしその主キーがすでに `second` データベースで使用されている場合、保存しようとするとエラーが発生します。

### 削除が行われるデータベースを選択する

デフォルトでは、既存のオブジェクトを削除する呼び出しは、最初にオブジェクトを取得するために使用したのと同じデータベース上で実行されます。

```pycon
>>> 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` データベースにマイグレーションする場合、以下のコマンドを使用します:

```pycon
>>> 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`](/ja/5.2/ref/contrib/admin/#django.contrib.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`](/ja/5.2/ref/contrib/admin/#django.contrib.admin.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`](/ja/5.2/ref/django-admin/#django-admin-migrate) がデータベースにテーブルを作成した直後に自動的に作成されます:

- デフォルトの `Site`、
- 各モデル (そのデータベースに保存されていないものも含む) の `ContentType` 、
- 各モデル（そのデータベースに保存されていないものも含む）の `Permission` 。

複数のデータベースを使用する通常のセットアップでは、これらのオブジェクトを複数のデータベースに持つことは有益ではありません。通常のセットアップには、プライマリ/レプリカや外部データベースへの接続などがあります。そのため、これら3つのモデルを1つのデータベースだけに同期させることができる [データベースルーター](#topics-db-multi-db-routing) を書くことを推奨します。複数のデータベースのテーブルを必要としないcontribやサードパーティアプリにも同じアプローチを使用してください。

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