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.
lihat juga
Lihat Dukungan banyak-basisdata 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
. 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'
}
}
If you attempt to access a database that you haven't defined in your
DATABASES
setting, Django will raise a
django.utils.connection.ConnectionDoesNotExist
exception.
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 diantaraobj1
danobj2
harus diizinkan,False
jika hubungan harus dicegah, atauNone
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
. MengembalikanTrue
jika tindakan harus berjalan,False
jika itu tidak harus berjalan, atauNone
jika perute tidak memiliki pendapat.Argumen penempatan
app_label
adalah label untuk aplikasi sedang dipindahkan.model_name
disetel oleh kebanyakan tindakan perpindahan pada nilai darimodel._meta.model_name
(versi huruf kecil dari model__name__
) dari model sedang dipindahkan. Nilai itu adalahNone
untuk tindakanRunPython
danRunSQL
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 jikaallow_migrate()
mengembalikanFalse
, tindakan perpindahan apapun untukmodel_name
akan secara diam dilewatkan ketika menjalankanmigrate
padadb
. Merubah perilaku dariallow_migrate()
untuk model yang sudah berpindah mungkin menghasilkan rusak dalam foreign key, tabel tambahan, atau tabel hilang. Ketikamakemigrations
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
).
The master 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 master router, providing a model and a hint (if
available). Django then tries each router in turn until a database
suggestion can be found. If no suggestion can be found, it tries the
current instance._state.db
of the hint
instance. If a hint instance wasn't provided, or instance._state.db
is None
, the master 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
. 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.
With this setup installed, and all databases migrated as per Sinkronisasi basisdata anda, lets run some Django code:
>>> # 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
¶
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()
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
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
dansites.Site
dapat disimpan dalam basisdata apapun, diberikan perute yang cocok. - Model-model
auth
—User
,Group
danPermission
— dikaitkan bersama-sama dan dikaitkan padaContentType
, sehingga mereka harus disimpan dalam basisdata sama sebagaiContentType
. admin
bergantung padaauth
, jadi modelnya harus di basisdata sama sepertiauth
.flatpages
danredirects
bergantung padasites
,jadi model-model mereka harus di basisdata yang sama sepertisites
.
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), - 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.
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.