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.

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

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

Jika anda berusaha mengakses basisdata yang anda belum menentukan dalam pengaturan setting:DATABASES anda, Django akan memunculkan sebuah pengecualian django.db.utils.ConnectionDoesNotExist.

Sinkronisasi basisdata anda

Perintah pengelolaan migrate berjalan pada satu basisdata pada satu waktu. Secara awalan, itu berjalan pada basisdata default, tetapi dengan menyediakan pilihan --database 1, anda dapat memberitahu itu untuk mensinkronkan basisdata berbeda. Jadi, untuk mensinkronkan semua kedalam semua basisdata dalam contoh pertama diatas, anda akan butuh memanggil:

$ ./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.

Jika, seperti dalam contoh kedua diatas, anda telah meninggalkan basisdata default kosong, anda harus menyediakan sebuah nama basisdata setiap waktu anda menjalankan migrate. Menghilangkan nama basisdata akan memunculkan sebuah kesalahan. Untuk contoh kedua:

$ ./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 -- mereka hanya berjalan pada satu basisdata pada satu waktu, menggunakan --database untuk mengendalikan penggunaan basisdata.

Sebuah pengecualian pada aturan ini adalah perintah 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() dari routers 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 dan 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 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 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 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

Perute basisdata dipasang menggunakan pengaturan DATABASE_ROUTERS. Pengaturan ini menentukan daftar dari nama-nama kelas, setiap menentukan perute harus digunakan dengan perute master (django.db.router).

Perute master digunakan oleh tindakan basisdata Django untuk memberikan penggunaan basisdata. Kapanpun sebuah permintaan membutuhkan untuk mengetahui basisdatamana digunakan, itu memanggil perute master, menyediakan sebuah model dan sebuah petunjuk (jika tersedia). Django kemudian mencoba setiap perute bergantian sampai saran basisdata dapat ditemukan. Jika tidak ada saran ditemukan, itu mencoba _state.db saat ini dari instance petunjuk. Jika sebuah instance petunjuk tidak disediakan, atau instance tidak saat ini mempunyai keadaan basisdata, perute master akan memperuntukkan basisdata default.

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',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'swordfish',
    },
    'primary': {
        'NAME': 'primary',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'spam',
    },
    'replica1': {
        'NAME': 'replica1',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'eggs',
    },
    'replica2': {
        'NAME': 'replica2',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'bacon',
    },
}

Sekarang kami akan butug menangani perutean. Pertama kami ingin sebuah perute yang mengetahui bagaimana mengirim permintaan untuk aplikasi auth pada auth_db:

class AuthRouter:
    """
    A router to control all database operations on models in the
    auth application.
    """
    def db_for_read(self, model, **hints):
        """
        Attempts to read auth models go to auth_db.
        """
        if model._meta.app_label == 'auth':
            return 'auth_db'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth models go to auth_db.
        """
        if model._meta.app_label == 'auth':
            return 'auth_db'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the auth app is involved.
        """
        if obj1._meta.app_label == 'auth' or \
           obj2._meta.app_label == 'auth':
           return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth app only appears in the 'auth_db'
        database.
        """
        if app_label == 'auth':
            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_list = ('primary', 'replica1', 'replica2')
        if obj1._state.db in db_list and obj2._state.db in db_list:
            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. 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 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.

Dengan pengaturan ini dipasang, mari kita jalankan beberapa kode 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')

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 sebelum anda berpindah. Lihat Perilaku dari aplikasi bantuan 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

Anda dapat memilih basisdata untuk QuerySet pada titik amnapun dalam rantai QuerySet. Cukup panggil using() pada QuerySet untuk mendapatkan QuerySet lain yang menggunakan basisdata khusus.

using() mengambil argumen tunggal: nama lain dari basisdata pada dimana anda ingin menjalankan permintaan. Sebagai contoh:

>>> # 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()

Memilih basisdata untuk save()

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

Sebagai contoh, untuk menyimpan sebuah obyek pada basisdata legacy_users, anda akan menggunakan ini:

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

Pertimbangkan contoh berikut

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

Anda dapat menghindari ini dalam dua cara. Pertama, anda dapat membersihkan primary key dari instance. Jika sebuah obyek tidak mempunyai primary key, Django akan memperlakukan itu sebagai sebuah obyek baru, menghindari kehilangan dari data pada basisdata 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.

Pilihan kedua adalah menggunakan pilihan force_insert pada save() untuk memastikan Django melakukan INSERT SQL:

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

Secara awalan, sebuah panggilan untuk menghapus obyek yang ada akan dijalankan pada basisdata sama yang digunakan untuk mengambil obyek dalam tempat pertama:

>>> 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().

Sebagai contoh, jika anda sedang memindahkan pengguna dari basisdata legacy_users ke basisdata new_users, anda mungkin menggunakan perintah-perintah ini:

>>> 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 penyesuaian yang akan langsung ke admin untuk menggunakan basisdata khusus untuk isi.

Obyek ModelAdmin mempunyai lima metode yang membutuhkan penyesuaian untuk dukungan banyak-basisdata:

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 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
cursor = connections['my_db_alias'].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 authUser, 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 membuat tabel untuk menahan mereka dalam basisdata:

  • Site awal,
  • sebuah ContentType untuk setiap model (termasuk itu tidak disimpan di basisdata itu),
  • tiga Permission untuk setiap model (termasuk itu tidak disimpan di basisdata itu),

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.

Peringatan

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.

Back to Top