---
title: "Basisdata banyak"
version: 4.2
locale: id
source: https://docs.djangoproject.com/id/4.2/topics/db/multi-db/
canonical: https://djangodocs.dev/id/4.2/topics/db/multi-db/
---
# Basisdata banyak

Panduan topik ini menggambarkan dukungan Django untuk interaksi dengan banyak basisdata. Kebanyakan dari sisa dokumentasi Djangomenganggap anda berinteraksi dengan basisdata tunggal. Jika anda ingin berinteraksi dengan banyak basisdata, anda akan butuh mengambil beberapa langkah-langkah tambahan.

> **See also**
>
> Lihat [Dukungan banyak-basisdata](/id/4.2/topics/testing/tools/#testing-multi-db) untuk informasi tentang percobaan dengan banyak basisdata.

## Menentukan basisdata anda

Langkah pertama untuk menggunakan lebih dari satu basisdata dengan Django adalah memberitahu Django tentang peladen basisdata anda akan gunakan. Ini dilakukan menggunakan pengaturan [`DATABASES`](/id/4.2/ref/settings/#std-setting-DATABASES). Pengaturan ini memetakan nama lain basisdata, yang adalah cara mengacu ke basisdata tertentu sepanjang Django, ke sebuah kamus dari pengaturan untuk hubungan tertentu itu. Pengaturan di sebelah dalam kamus digambarkan sepenuhnya dalam dokumentasi [`DATABASES`](/id/4.2/ref/settings/#std-setting-DATABASES).

Basisdata dapat mempunyai nama lain apapun anda pilih. Bagaimanapun, nama lain `default` mempunyai makna khusus. Django menggunakan basisdata dengan nama lain dari `default` ketika tidak ada lagi basisdata telah dipilih.

Berikut adalah sebuah contoh potongan `settings.py` menentukan dua basisdata -- sebuah awalan basisdata PostgreSQL dan basisdata MySQL disebut `users`:

```
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",
    },
}
```

Jika konsep dari basisdata `default` tidak masuk akal dalam konteks proyek anda, anda butuh berhati-hati untuk selalu menentukan basisdata anda ingin gunakan. Django membutuhkan masukan basisdata `default` untuk ditentukan, tetapi parameter dictionary dapat berupa kosong jika itu akan tidak digunakan. Untuk melakkukan ini, anda harus menyetel [`DATABASE_ROUTERS`](/id/4.2/ref/settings/#std-setting-DATABASE_ROUTERS) untuk semua dari model aplikasi anda, termasuk itu dalam bantuan dan aplikasi pihak-ketiga apapun anda sedang gunakan, sehingga tidak ada permintaan ke basisdata awalan. Berikut adalah contoh potongan `settings.py` menentukan basisdata dua bukan-awalan, dengan masukan `default` sengaja dibiarkan kosong:

```
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",
    },
}
```

If you attempt to access a database that you haven't defined in your
[`DATABASES`](/id/4.2/ref/settings/#std-setting-DATABASES) setting, Django will raise a
`django.utils.connection.ConnectionDoesNotExist` exception.

## Sinkronisasi basisdata anda

The [`migrate`](/id/4.2/ref/django-admin/#django-admin-migrate) management command operates on one database at a
time. By default, it operates on the `default` database, but by
providing the [`--database`](/id/4.2/ref/django-admin/#cmdoption-migrate-database) option, you can tell it
to synchronize a different database. So, to synchronize all models onto
all databases in the first example above, you would need to call:

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

Jika anda tidak ingin setiap aplikasi disinkronkan kedalam basisdata tertentu, anda dapat menentukan database router1 yang menerapkan batasan kebijakan ketersediaan dari model tertentu.

If, as in the second example above, you've left the `default` database empty,
you must provide a database name each time you run [`migrate`](/id/4.2/ref/django-admin/#django-admin-migrate). Omitting
the database name would raise an error. For the second example:

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

### Menggunakan perintah pengelolaan lain

Kebanyakan perintah `django-admin` lain yang berinteraksi dengan basisdata berjalan dalam cara sama seperti [`migrate`](/id/4.2/ref/django-admin/#django-admin-migrate) -- mereka hanya berjalan pada satu basisdata pada satu waktu, menggunakan `--database` untuk mengendalikan penggunaan basisdata.

Sebuah pengecualian pada aturan ini adalah perintah [`makemigrations`](/id/4.2/ref/django-admin/#django-admin-makemigrations). Itu mengecek riwayat perpindahan di basisdata untuk menangkap masalah dengan berkas perpindahan yang ada (yang dapat disebabkan dengan menyunting mereka) sebelum membuat perpindahan baru. Secara awalan, itu memeriksa hanya basisdata `default`, tetapi itu merundingkan metode [`allow_migrate()`](#allow_migrate) dari [routers](#topics-db-multi-db-routing) jika apapun terpasang.

## Perute basisdata otomatis

Cara termudah menggunakan banyak basisdata adalah menyetel skema perutean basisdata. Skema perutean awalan memastikan bahwa obyek tetap 'sticky' ke basisdata aslinya (yaitu, obyek diambil dari basisdata `foo` akan disimpan pada basisdata sama). Skema perute awalan memastikan bahwa jika sebuah absisdata tidak ditentukan, semua permintaan kembali ke basisdata `default`.

Anda tidak perlu melakukan apapun untuk mengaktifkan skema perutean awalan -- itu disediakan 'beda dari biasanya' pada setiap proyek Django. Bagaimanapun, jika anda ingin menerapkan lebih menarik perilaku peruntukan basisdata, anda dapat menentukan dan memasang perute basisdata anda sendiri.

### Router basisdata

Perute basisdata adalah kelas yang menyediakan sampai empat metode:

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

Sarankan basisdata yang harus digunakan untuk membaca tindakan-tindakan untuk obyek dari jenis `model`.

Jika tindakan basisdata dapat menyediakan informasi tambahan apapun yang mungkin membantu dalam memilih basisdata, itu akan menyediakan dalam dictionary `hints`. Rincian pada peunjuk sah disediakan below 1.

Mengembalikan `None` jika tidak ada saran.

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

Sarankan basisdata yang harus digunakan untuk menulis dari obyek dari jenis Model.

Jika tindakan basisdata dapat menyediakan informasi tambahan apapun yang mungkin membantu dalam memilih basisdata, itu akan menyediakan dalam dictionary `hints`. Rincian pada peunjuk sah disediakan below 1.

Mengembalikan `None` jika tidak ada saran.

#### `allow_relation(obj1, obj2, **hints)`

Mengembalikan `True` jika sebuah hubungan diantara `obj1` dan `obj2` harus diizinkan, `False` jika hubungan harus dicegah, atau `None` jika perute tidak memiliki pendapat. Ini adalah murni tindakan pengesahan, digunakan oleh foreign key dan tindakan many to many untuk menentukan jika hubungan harus diizinkan diantara dua obyek.

If no router has an opinion (i.e. all routers return `None`), only
relations within the same database are allowed.

#### `allow_migrate(db, app_label, model_name=None, **hints)`

Tentukan jika tindakan perpindahan diizinkan untuk menjalankan pada basisdata dengan nama lain `db`. Mengembalikan `True` jika tindakan harus berjalan, `False` jika itu tidak harus berjalan, atau `None` jika perute tidak memiliki pendapat.

Argumen penempatan `app_label` adalah label untuk aplikasi sedang dipindahkan.

`model_name` disetel oleh kebanyakan tindakan perpindahan pada nilai dari `model._meta.model_name` (versi huruf kecil dari model `__name__`) dari model sedang dipindahkan. Nilai itu adalah `None` untuk tindakan [`RunPython`](/id/4.2/ref/migration-operations/#django.db.migrations.operations.RunPython) dan [`RunSQL`](/id/4.2/ref/migration-operations/#django.db.migrations.operations.RunSQL) meskipun mereka menyediakan itu menggunakan petunjuk.

`hints` digunakan oleh tindakan tertentu untuk berkomunikasi informasi tambahan ke perute.

Ketika `hints` disetel, `hints` biasanya mengandung kelas model dibawah kunci `'model'`. Catat bahwa itu mungkin berupa historical model 1, dan dengan demikian tidak mempunyai atribut penyesuaian apapun, metode, atau pengelola. Anda harus hanya bergantung pada `_meta`.

Metode ini dapat juga digunakan untuk menentukan ketersediaan dari sebuah model pada basisdata yang diberikan.

[`makemigrations`](/id/4.2/ref/django-admin/#django-admin-makemigrations) selalu membuat perpindahan untuk perubahan model, tetapi jika `allow_migrate()` mengembalikan `False`, tindakan perpindahan apapun untuk `model_name` akan secara diam dilewatkan ketika menjalankan [`migrate`](/id/4.2/ref/django-admin/#django-admin-migrate) pada `db`. Merubah perilaku dari `allow_migrate()` untuk model yang sudah berpindah mungkin menghasilkan rusak dalam foreign key, tabel tambahan, atau tabel hilang. Ketika [`makemigrations`](/id/4.2/ref/django-admin/#django-admin-makemigrations) memeriksa riwayat perpindahan, itu melewati basisdata dimana tidak ada aplikasi diizinkan berpindah.

Perute tidak harus menyediakan *semua* metode ini -- itu mungkin menghilangkan satu atau lebih dari mereka. Jika satu dari metode ini dihilangkan, Django akan melewati perute itu ketika melakukan pemeriksaan terkait.

#### Petunjuk

Petunjuk diterima oleh perute basisdata dapat digunakan untuk memutuskan basisdata mana harus menerima permintaan yang diberikan.

Saat sekarang, petunjuk satu-satunya akan disediakan adalah `instance`, sebuah instance obyek yang terkait ke tindakan baca atau tulis yang berlangsung. Ini mungkin instance yang sedang disimpan, atau itu mungkin berupa sebuah instance yang sedang ditambahkan dalam hubungan many-to-many. Dalam beberapa kasus, tidak ada petunjuk instance akan disediakan sama sekali. Perute memeriksa untuk kehadiran dari sebuah petunjuk instance, dan menentukan jika petunjuk itu harus digunakan untuk merubah perulaku perutean.

### Menggunakan router

Database routers are installed using the [`DATABASE_ROUTERS`](/id/4.2/ref/settings/#std-setting-DATABASE_ROUTERS)
setting. This setting defines a list of class names, each specifying a
router that should be used by the base router
(`django.db.router`).

The base router is used by Django's database operations to allocate
database usage. Whenever a query needs to know which database to use,
it calls the base router, providing a model and a hint (if
available). The base router tries each router class in turn until one returns
a database suggestion. If no routers return a suggestion, the base router tries
the current [`instance._state.db`](/id/4.2/ref/models/instances/#django.db.models.Model._state) of the hint instance. If no hint instance
was provided, or [`instance._state.db`](/id/4.2/ref/models/instances/#django.db.models.Model._state) is
`None`, the base router will allocate the `default` database.

### Sebuah contoh

> **Hanya bertujuan contoh!**
>
> Contoh ini dimaksudkan sebagai pertunjukan dari bagaimana infrastruktur perute dapat digunakan untuk mengubah penggunaan basisdata. Itu sengaja mengabaikan beberapa masalah rumit untuk mempertunjukkan bagaimana perute digunakan.
>
> Contoh ini tidak akan bekerja jika apapun dari model dalam `myapp` mengandung hubungan pada model diluar dari basisdata `other`. Cross-database relationships 1 memperkenalkan masalah kesatuan referensial yang Django tidak dapat saat ini ditangani.
>
> Konfigurasi utama/tiruan (mengacu pada sebagai master/slave oleh beberapa basisdata) digambarkan juga cacat -- itu tidak menyediakan pemecahan apapun untuk menangani tiruan ketinggalan (yaitu permintaan ketidakkonsekuen diperkenalkan karena dari waktu diambil untuk menulis untuk disebarkan ke tiruan). Itu juga tidak mempertimbangkan timbal balik dari transaksi dengan strategi penggunaan basisdata.

Jadi -  apa ini artinya dalam praktik? Mari kita pertimbangkan konfigurasi contoh lain. Satu ini akan mempunyai beberapa basisdata: satu untuk aplikasi `auth`, dan semua aplikasi lain menggunakan setelah utama/tiruan dengan duatiruan baca. Ini adalah pengaturan menentukan basisdata ini:

```
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",
    },
}
```

Now we'll need to handle routing. First we want a router that knows to
send queries for the `auth` and `contenttypes` apps to `auth_db`
(`auth` models are linked to `ContentType`, so they must be stored in the
same database):

```
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
```

Dan kami juga ingin sebuah perute yang mengirim semua aplikasi lain semua ke konfigurasi utama/tiruan, dan secara acak memilih sebuah tiruan untuk dibaca:

```
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
```

Akhirnya, dalam berkas pengaturan, kami menambahkan berikut (mengganti `path.to.` dengan jalur Python sebenarnya pada modul dimana perute ditentukan):

```
DATABASE_ROUTERS = ["path.to.AuthRouter", "path.to.PrimaryReplicaRouter"]
```

Urutan dimana perute diolah adalah penting. Perute akan diminta agar mereka didaftarkan dalam pengaturan [`DATABASE_ROUTERS`](/id/4.2/ref/settings/#std-setting-DATABASE_ROUTERS). Dalam contoh ini, `AuthRouter` diolah sebelum `PrimaryReplicaRouter`, dan sebagai hasil, keputusan tentang model-model dalam `auth` diolah sebelum keputusan lain apapun dibuat. Jika pengaturan  [`DATABASE_ROUTERS`](/id/4.2/ref/settings/#std-setting-DATABASE_ROUTERS) mendaftarkan dua perute dalam urutan lain, `PrimaryReplicaRouter.allow_migrate()` akan diolah dahulu. Tangkap-semua alami dari penerapan PrimaryReplicaRouter akan berarti bahwa semua model-model akan tersedia pada semua basisdata.

With this setup installed, and all databases migrated as per
[Sinkronisasi basisdata anda](#synchronizing-multiple-databases), lets run some Django code:

```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")
```

Contoh ini menentukan sebuah perute untuk menangani interaksi dengan model-model dari aplikasi `auth`, dan perute lain untuk mengangani interaksi dengan semua aplikasi lain. Jika anda membiarkan basisdata `default` anda kosong dan tidak ingin menentukan perute basisdata tangkap-semua untuk mengangani semua aplikasi tidak sebaliknya ditentukan, perute anda harus menangani nama-nama dari semua aplikasi dalam [`INSTALLED_APPS`](/id/4.2/ref/settings/#std-setting-INSTALLED_APPS) sebelum anda berpindah. Lihat [Perilaku dari aplikasi bantuan](#contrib-app-multiple-databases) untuk informasi tentang apliaksi bantuan yang harus bersama-sama dalam satu basisdata.

## Manual memilih basisdata

Django juga menyediakan sebuah API yang mengizinkan anda merawat kendali lengkap terhadap penggunaan basisdata dalam kode anda. Peruntukan basisdata ditentukan manual terhadap basisdata diperuntukkan oleh sebuah perute.

### Secara manual memilih basisdata untuk `QuerySet`

You can select the database for a `QuerySet` at any point in the
`QuerySet` "chain." Call `using()` on the `QuerySet` to get another
`QuerySet` that uses the specified database.

`using()` takes a single argument: the alias of the database on
which you want to run the query. For example:

```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")
```

### Memilih basisdata untuk `save()`

Gunakan kata kunci `using` pada `Model.save()` untuk menentukan pada basisdata mana data harus disimpan.

For example, to save an object to the `legacy_users` database, you'd
use this:

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

Jika anda tidak menentukan `using`, metode `save()` kan menyimpan kedalam basisdata awalan ditempatkan oleh perute.

#### Memindahkan sebuah obyek dari satu basisdata ke lainnya

Jika anda menyimpan sebuah instance pada satu basisdata, itu mungkin menggoda untuk menggunakan `save(using=...)` sebagai sebuah cara berpindah instance ke basisdata baru. Bagaimanapun, jika anda tidak mengambil langkah-langkah yang sesuai, ini dapat memiliki beberapa konsekuensi tidak diharapkan.

Consider the following example:

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

Dalam pernyataan 1, sebuah obyek `Person` baru disimpan ke basisdata `first`. Pada saat ini, `p` tidak memiliki primary key, jadi Django menerbitkan sebuah pernyataan SQL `INSERT`. Ini membuat sebuah primary key, dan Django memberikan primary key itu ke `p`.

Ketika penyimpanan muncul dalam pernyataan 2, `p` sudah mempunyai nilai primary key, dan Django akan berusaha menggunakan primary key itu pada basisdata baru. Jika nilai primary key tidak digunakan dalam basisdata `second`, kemudian akdan tidak mempunyai masalah apapun -- obyek akan disalin ke basisdata baru.

Bagaimanapun, jika primary key dari `p` sudah digunakan pada basisdata `second`, obyek yang ada dalam basisdata `second` akan ditimpan ketika `p` disimpan.

You can avoid this in two ways. First, you can clear the primary key
of the instance. If an object has no primary key, Django will treat it
as a new object, avoiding any loss of data on the `second`
database:

```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.
```

The second option is to use the `force_insert` option to `save()`
to ensure that Django does an SQL `INSERT`:

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

Ini akan memastikan bahwa seseorang bernama `Fred` akan mempunyai primary key sama pada kedua basisdata. Jika primary key sudah digunakan ketika anda mencoba menyimpan kedalam basisdata `kedua`, sebuah kesalahan akan dimunculkan.

### Memilih basisdata untuk menghapus dari

By default, a call to delete an existing object will be executed on
the same database that was used to retrieve the object in the first
place:

```pycon
>>> u = User.objects.using("legacy_users").get(username="fred")
>>> u.delete()  # will delete from the `legacy_users` database
```

Untuk menentukan basisdata dari model mana akan dihapus, lewatkan sebuah argumen kata kunci `using` pada metode `Model.delete()`. Argumen ini bekerja seperti argumen kata kunci `using` pada `save()`.

For example, if you're migrating a user from the `legacy_users`
database to the `new_users` database, you might use these commands:

```pycon
>>> user_obj.save(using="new_users")
>>> user_obj.delete(using="legacy_users")
```

### Menggunakan pengelola dengan banyak basisdata

Gunakan metode `db_manager()` pada pengelola untuk memberikan pengelola mengakses ke basisdata bukan-awalan.

Sebagai contoh, katakan anda mempunyai metode pengelolaan penyesuaian yang menyentuh basisdata -- `User.objects.create_user()`. Karena `create_user()` adalah metode pengelola, bukan metode `QuerySet`, anda tidak dapat melakukan `User.objects.using('new_users').create_user()`. (Metode `create_user()` hanya tersedia pada `User.objects`, pengelola, bukan pada obyek `QuerySet` diturunkan dari pengelola.) Pemecahannya adalah menggunakan `db_manager()`, seperti ini:

```
User.objects.db_manager("new_users").create_user(...)
```

`db_manager()` mengembalikan sebuah salinan dari ikatan pengelola pada basisdata anda tentukan.

#### Menggunakan `get_queryset()` dengan basisdata banyak

Jika anda menimpa `get_queryset()` pada pengelola anda, apstikan untuk antara memanggil metode pada induk (menggunakan `super()`) atau melakukan penanganan sesuai dari atribut `_db` pada pengelola (sebuah string mengandung nama dari basisdata untuk digunakan).

Sebagai contoh, jika anda ingin mengembalikan penyesuaian kelas `QuerySet` dari metode `get_queryset`, anda dapat melakukan ini:

```
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
```

## Memamerkan basisdata banyak di antarmuka admin Django

Admin Django tidak mempunyai dukungan jelas untuk banyak basisdata. Jika anda ingin menyediakan sebuah antarmuka admin untuk sebuah model pada sebuah basisdata daripada selain ditentukan oleh rantai peute anda, anda akan butuh menulis kelas-kelas [`ModelAdmin`](/id/4.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin) penyesuaian yang akan langsung ke admin untuk menggunakan basisdata khusus untuk isi.

`ModelAdmin` objects have the following methods that require customization
for multiple-database support:

```
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
        )
```

Penerapan disediakan disini menerapkan strategi banyak-basisdata dimana semua obyek dari jenis yang diberikan disimpan pada basisdata khusus (sebagai contoh, semua obyek `User` dalam basisdata `lain`). Jika penggunaan anda dari banyak basisdata lebih rumit, `ModelAdmin` anda akan butuh mencerminkan strategi itu.

Obyek [`InlineModelAdmin`](/id/4.2/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin) dapat ditangani di gaya yang mirip. Mereka membutuhkan tiga metode penyesuaian:

```
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
        )
```

Sekali anda telah menulis pengertian admin model anda, mereka dapat didaftarkan dengan instance `Admin` apapun:

```
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)
```

Contoh ini menyetel dua situs admin. Pada situs pertama, obyek-obyek `Author` dan `Publisher` dibuka; obyek-obyek `Publisher` mempunyai sebuah dibarisan datar menunjukkan buku-buku diterbitkan oleh penerbit. Situs kedua membuka hanya penerbit, tanpa barisan.

## Menggunakan kursor mentah dengan banyak basisdata

Jika anda menggunakan lebih dari satu basisdata anda dapat menggunakan `django.db.connections` untuk mengambil hubungan (dan kursor) untuk basisdata tertentu. `django.db.connections` adalah objek seperti-kamus yang mengizinkan anda mengambil hubungan tertentu menggunakan nama lainnya:

```
from django.db import connections

with connections["my_db_alias"].cursor() as cursor:
    ...
```

## Batasan dari banyak basisdata

### Hubungan lintas-basisdata

Django saat ini tidak menyediakan dukungan apapun untuk foreign key atau hubungan many-to-many menjangkau banyak basisdata. Jika anda telah menggunakan sebuah perute pada model sebagian ke basisdata berbeda, foreign key apapun dan hubungan many-to-many ditentukan oleh modek-model tersebut harus secara internal pada basisdata tunggal.

Ini karena dari kesatuan referensial. Untuk merawat hubungan diantara dua obyek, Django butuh mengetahui bahwa primary key dari obyek terkait adalah sah. Jika primary key disimpan pada basisdata terpisah, itu tidak mungkin dengan mudah menilai keabsahan primary key.

Jika anda sedang menggunakan Postgres, Oracle, atau MySQL dengan InnoDB, ini dipaksa pada tingkat kesatuan basisdata -- batasan kunci tingkatan basisdata mencegah dari pembuatan dari hubungan yang tidak dapat disahkan.

Bagaimanapun, jika anda sedang menggunakan SQLite atay MySQL dengan tabel MyISAM, tidak ada pemaksaan kesatuan referensial; sebagai hasil, anda mungkin dapat me 'niru' foreign key basisdata. bagaimanapun, konfigurasi ini tidak secara resmi didukung oleh Django.

### Perilaku dari aplikasi bantuan

Beberapa aplikasi bantuan termasuk model-model, dan beberapa aplikasi bergantung pada lainnya. Sejak hubungan silang-basisdata tidak dimungkinkan, ini membuat beberapa pembatasan pada bagaimana anda dapat memisahkan model-model ini terhadap basisdata:

- setiap satu dari `contenttypes.ContentType`, `sessions.Session` dan `sites.Site` dapat disimpan dalam basisdata apapun, diberikan perute yang cocok.
- Model-model `auth` — `User`, `Group` dan `Permission` — dikaitkan bersama-sama dan dikaitkan pada `ContentType`, sehingga mereka harus disimpan dalam basisdata sama sebagai `ContentType`.
- `admin` bergantung pada `auth`, jadi modelnya harus di basisdata sama seperti `auth`.
- `flatpages` dan `redirects` bergantung pada `sites`,jadi model-model mereka harus di basisdata yang sama seperti `sites`.

Sebagai tambahan, beberapa obyek otomatis dibuat hanya setelah [`migrate`](/id/4.2/ref/django-admin/#django-admin-migrate) membuat tabel untuk menahan mereka dalam basisdata:

- `Site` awal,
- sebuah `ContentType` untuk setiap model (termasuk itu tidak disimpan di basisdata itu),
- the `Permission`s for each model (including those not stored in that
  database).

Untuk pengaturan umum dengan banyak basisdata, itu tidak berguna memiliki obyek-obyek ini dalam lebih dari satu basisdata. Pengaturan umum menyertakan utama/tiruan dan menghubungkan ke basisdata luar. Karena itu, itu dianjurkan untuk menulis database router1 yang mengizinkan mensinkronkan ketiga model ini pada hanya satu basisdata. Gunakan pendekatan sama untuk aplikasi bantuan dan pihak-ketiga yang tidak butuh tabel mereka dalam banyak basisdata.

> **Warning**
>
> Jika anda sedang mensinkronkan jenis-jenis isi ke lebih dari satu basisdata, waspada bahwa primary key mereka mungkin tidak cocok terhadap basisdata. Ini mungkin menghasilkan kerusakan data atau kehilangan data.
