Flera databaser¶
Denna ämnesguide beskriver Djangos stöd för att interagera med flera databaser. Det mesta av resten av Djangos dokumentation förutsätter att du interagerar med en enda databas. Om du vill interagera med flera databaser måste du vidta några ytterligare åtgärder.
Se även
Se Stöd för flera databaser för information om testning med flera databaser.
Definiera dina databaser¶
Det första steget för att använda mer än en databas med Django är att berätta för Django om de databasservrar du kommer att använda. Detta görs med hjälp av inställningen DATABASES
. Denna inställning mappar databasalias, som är ett sätt att hänvisa till en specifik databas i hela Django, till en ordbok med inställningar för den specifika anslutningen. Inställningarna i de inre ordböckerna beskrivs i sin helhet i DATABASES
-dokumentationen.
Databaser kan ha vilket alias du vill. Aliaset default
har dock en speciell betydelse. Django använder databasen med aliaset default
när ingen annan databas har valts.
Följande är ett exempel på settings.py
snutt som definierar två databaser - en standard PostgreSQL-databas och en MySQL-databas som heter 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",
},
}
Om konceptet med en default
databas inte är meningsfullt i samband med ditt projekt, måste du vara noga med att alltid ange den databas som du vill använda. Django kräver att en default
databaspost definieras, men parameterordlistan kan lämnas tom om den inte kommer att användas. För att göra detta måste du ställa in DATABASE_ROUTERS
för alla dina appars modeller, inklusive de i alla contrib- och tredjepartsappar som du använder, så att inga frågor dirigeras till standarddatabasen. Följande är ett exempel på en settings.py
snutt som definierar två icke-standarddatabaser, med default
posten avsiktligt lämnad tom:
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",
},
}
Om du försöker komma åt en databas som du inte har definierat i din DATABASES
-inställning, kommer Django att göra ett django.utils.connection.ConnectionDoesNotExist
undantag.
Synkronisering av dina databaser¶
Ledningskommandot migrate
arbetar med en databas i taget. Som standard används databasen default
, men genom att ange alternativet --database
kan du be kommandot att synkronisera en annan databas. Så för att synkronisera alla modeller till alla databaser i det första exemplet ovan måste du anropa:
$ ./manage.py migrate
$ ./manage.py migrate --database=users
Om du inte vill att alla program ska synkroniseras med en viss databas kan du definiera en :ref:databasrouter<topics-db-multi-db-routing>
som implementerar en policy som begränsar tillgängligheten för vissa modeller.
Om du, som i det andra exemplet ovan, har lämnat databasen default
tom, måste du ange ett databasnamn varje gång du kör migrate
. Om du utelämnar databasnamnet kommer du att få ett felmeddelande. För det andra exemplet:
$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=customers
Använda andra hanteringskommandon¶
De flesta andra kommandon i django-admin
som interagerar med databasen fungerar på samma sätt som migrate`
- de fungerar bara på en databas i taget och använder --database
för att styra vilken databas som används.
Ett undantag från denna regel är kommandot makemigrations
. Det validerar migreringshistoriken i databaserna för att upptäcka problem med de befintliga migreringsfilerna (som kan orsakas av att de redigerats) innan nya migreringar skapas. Som standard kontrolleras endast databasen default
, men metoden allow_migrate`()
i routers konsulteras om någon sådan finns installerad.
Automatisk routning av databaser¶
Det enklaste sättet att använda flera databaser är att konfigurera ett routningsschema för databaser. Standarddirigeringsschemat säkerställer att objekt förblir ”klibbiga” till sin ursprungliga databas (dvs. ett objekt som hämtas från databasen foo
kommer att sparas i samma databas). Standarddirigeringsschemat säkerställer att om en databas inte anges, går alla frågor tillbaka till standard
-databasen.
Du behöver inte göra någonting för att aktivera standardroutningsschemat - det tillhandahålls ”direkt” i alla Django-projekt. Men om du vill implementera mer intressanta beteenden för databasallokering kan du definiera och installera dina egna databasroutrar.
Databasroutrar¶
En databasrouter är en klass som tillhandahåller upp till fyra metoder:
- db_for_read(model, **hints)¶
Föreslå den databas som bör användas för läsoperationer för objekt av typen
model
.Om en databasoperation kan tillhandahålla ytterligare information som kan hjälpa till att välja en databas, kommer den att tillhandahållas i ordlistan
hints
. Detaljer om giltiga hintar finns under.Returnerar
None
om det inte finns något förslag.
- db_for_write(model, **hints)¶
Föreslå vilken databas som bör användas för skrivningar av objekt av typen Model.
Om en databasoperation kan tillhandahålla ytterligare information som kan hjälpa till att välja en databas, kommer den att tillhandahållas i ordlistan
hints
. Detaljer om giltiga hintar finns under.Returnerar
None
om det inte finns något förslag.
- allow_relation(obj1, obj2, **hints)¶
Returnerar
True
om en relation mellanobj1
ochobj2
bör tillåtas,False
om relationen bör förhindras, ellerNone
om routern inte har någon åsikt. Detta är en ren valideringsoperation som används av foreign key och many to many-operationer för att avgöra om en relation ska tillåtas mellan två objekt.Om ingen router har en åsikt (d.v.s. alla routrar returnerar
None
), är endast relationer inom samma databas tillåtna.
- allow_migrate(db, app_label, model_name=None, **hints)¶
Avgör om migreringsoperationen får köras på databasen med aliaset
db
. ReturnerarTrue
om åtgärden ska köras,False
om den inte ska köras, ellerNone
om routern inte har någon åsikt.Det positionella argumentet
app_label
är etiketten för den applikation som migreras.model_name
sätts av de flesta migreringsoperationer till värdet avmodel._meta.model_name
(den gemena versionen av modellens__name__
) för den modell som migreras. Dess värde ärNone
för operationernaRunPython
ochRunSQL
om de inte tillhandahåller det med hjälp av tips.hints
används av vissa operationer för att kommunicera ytterligare information till routern.När
model_name
är inställt innehållerhints
normalt modellklassen under nyckeln'model'
. Observera att det kan vara en historisk modell, och därmed inte ha några anpassade attribut, metoder eller hanterare. Du bör bara förlita dig på_meta
.Denna metod kan också användas för att avgöra om en modell finns tillgänglig i en viss databas.
makemigrations
skapar alltid migreringar för modelländringar, men omallow_migrate()
returnerarFalse
, kommer alla migreringsåtgärder förmodel_name
att tyst hoppas över när du körmigrate
pådb
. Att ändra beteendet förallow_migrate()
för modeller som redan har migreringar kan resultera i trasiga utländska nycklar, extra tabeller eller tabeller som saknas. Närmakemigrations
verifierar migreringshistoriken hoppar den över databaser där ingen app tillåts migrera.
En router behöver inte tillhandahålla alla dessa metoder - den kan utelämna en eller flera av dem. Om en av metoderna utelämnas kommer Django att hoppa över den routern när den utför den relevanta kontrollen.
Tips¶
De tips som databasroutern tar emot kan användas för att avgöra vilken databas som ska ta emot en viss förfrågan.
För närvarande är den enda ledtråd som kommer att ges instance
, en objektinstans som är relaterad till den läs- eller skrivoperation som pågår. Det kan vara den instans som sparas, eller en instans som läggs till i en många-till-många-relation. I vissa fall kommer ingen instanshint att tillhandahållas alls. Routern kontrollerar om det finns en instanshint och avgör om denna hint ska användas för att ändra routningsbeteendet.
Använda routrar¶
Databasroutrar installeras med hjälp av inställningen DATABASE_ROUTERS
. Den här inställningen definierar en lista med klassnamn som var och en anger en router som ska användas av basroutern (django.db.router
).
Basroutern används av Djangos databasoperationer för att fördela databasanvändning. När en fråga behöver veta vilken databas som ska användas, anropar den basroutern och tillhandahåller en modell och en ledtråd (om tillgänglig). Basroutern provar varje routerklass i tur och ordning tills en av dem returnerar ett databasförslag. Om inga routrar returnerar ett förslag försöker basroutern med den aktuella instance._state.db
i hint-instansen. Om ingen hint-instans tillhandahölls, eller om instance._state.db
är None
, kommer basroutern att allokera default
-databasen.
Ett exempel¶
Endast i exempelsyfte!
Detta exempel är avsett som en demonstration av hur routerinfrastrukturen kan användas för att ändra databasanvändningen. Det bortser avsiktligt från vissa komplexa frågor för att visa hur routrar används.
Det här exemplet fungerar inte om någon av modellerna i myapp
innehåller relationer till modeller utanför andra
databasen. :ref:``Relationer mellan databaser <no_cross_database_relations>` introducerar problem med referensintegritet som Django för närvarande inte kan hantera.
Den beskrivna konfigurationen med primär/replik (som i vissa databaser kallas master/slave) är också bristfällig - den ger ingen lösning för att hantera replikationsfördröjning (dvs. inkonsekvenser i frågor som uppstår på grund av den tid det tar för en skrivning att spridas till replikerna). Den tar inte heller hänsyn till transaktionernas samspel med strategin för databasutnyttjande.
Så - vad innebär detta i praktiken? Låt oss överväga en annan exempelkonfiguration. Den här kommer att ha flera databaser: en för auth
-applikationen och alla andra appar som använder en primär / replika-installation med två läsrepliker. Här är inställningarna som specificerar dessa databaser:
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",
},
}
Nu måste vi hantera routning. Först vill vi ha en router som vet att skicka frågor för apparna auth
och contenttypes
till auth_db
(auth
modeller är länkade till ContentType
, så de måste lagras i samma databas):
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
Och vi vill också ha en router som skickar alla andra appar till konfigurationen primär/replika och slumpmässigt väljer en replika att läsa från:
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
Slutligen lägger vi till följande i inställningsfilen (ersätter path.to.
med den faktiska Python-sökvägen till den eller de moduler där routrarna definieras):
DATABASE_ROUTERS = ["path.to.AuthRouter", "path.to.PrimaryReplicaRouter"]
Den ordning i vilken routrarna behandlas är viktig. Routrar kommer att efterfrågas i den ordning de listas i DATABASE_ROUTERS
. I det här exemplet bearbetas AuthRouter
före PrimaryReplicaRouter
, vilket innebär att beslut som rör modellerna i auth
bearbetas innan något annat beslut fattas. Om inställningen DATABASE_ROUTERS
hade listat de två routrarna i en annan ordning skulle PrimaryReplicaRouter.allow_migrate()
bearbetas först. PrimaryReplicaRouter-implementeringens catch-all-karaktär skulle innebära att alla modeller skulle vara tillgängliga i alla databaser.
Med den här installationen installerad och alla databaser migrerade enligt Synkronisering av dina databaser, kan vi köra lite Django-kod:
>>> # 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")
I det här exemplet definierades en router för att hantera interaktion med modeller från appen auth
och andra routrar för att hantera interaktion med alla andra appar. Om du har lämnat din default
-databas tom och inte vill definiera en allomfattande databasrouter för att hantera alla appar som inte anges på annat sätt, måste dina routrar hantera namnen på alla appar i INSTALLED_APPS
innan du migrerar. Se Beteende hos Contrib-appar för information om contrib-appar som måste vara samlade i en databas.
Manuellt val av databas¶
Django tillhandahåller också ett API som gör att du kan behålla fullständig kontroll över databasanvändningen i din kod. En manuellt angiven databasallokering kommer att prioriteras framför en databas som allokerats av en router.
Manuellt val av databas för en QuerySet
¶
Du kan välja databas för ett QuerySet
när som helst i QuerySet
”kedjan” Anropa using()
på QuerySet
för att få ett annat QuerySet
som använder den angivna databasen.
using()
tar ett enda argument: aliaset för den databas som du vill köra frågan på. Till exempel:
>>> # 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")
Välja en databas för save()
¶
Använd nyckelordet using
till Model.save()
för att ange till vilken databas data ska sparas.
Om du t.ex. vill spara ett objekt i databasen legacy_users
använder du följande:
>>> my_object.save(using="legacy_users")
Om du inte anger using
kommer metoden save()
att spara i den standarddatabas som routrarna har tilldelat.
Flytta ett objekt från en databas till en annan¶
Om du har sparat en instans i en databas kan det vara frestande att använda save(using=...)
som ett sätt att migrera instansen till en ny databas. Men om du inte vidtar lämpliga åtgärder kan detta få oväntade konsekvenser.
Tänk på följande exempel:
>>> p = Person(name="Fred")
>>> p.save(using="first") # (statement 1)
>>> p.save(using="second") # (statement 2)
I uttalande 1 sparas ett nytt Person
-objekt i databasen first
. Vid denna tidpunkt har p
ingen primärnyckel, så Django utfärdar en SQL INSERT
-sats. Detta skapar en primärnyckel och Django tilldelar den primära nyckeln till p
.
När sparandet sker i uttalande 2 har p
redan ett primärnyckelvärde, och Django kommer att försöka använda den primärnyckeln i den nya databasen. Om det primära nyckelvärdet inte används i den andra
databasen, kommer du inte att ha några problem - objektet kommer att kopieras till den nya databasen.
Men om primärnyckeln i p
redan används i databasen second
, kommer det befintliga objektet i databasen second
att åsidosättas när p
sparas.
Du kan undvika detta på två sätt. För det första kan du rensa instansens primära nyckel. Om ett objekt inte har någon primärnyckel kommer Django att behandla det som ett nytt objekt, vilket undviker förlust av data i andra
databasen:
>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.pk = None # Clear the primary key.
>>> p.save(using="second") # Write a completely new object.
Det andra alternativet är att använda alternativet force_insert
till save()
för att säkerställa att Django gör en SQL INSERT
:
>>> p = Person(name="Fred")
>>> p.save(using="first")
>>> p.save(using="second", force_insert=True)
Detta kommer att säkerställa att personen som heter Fred
kommer att ha samma primärnyckel i båda databaserna. Om den primära nyckeln redan används när du försöker spara i den ”andra” databasen, kommer ett fel att uppstå.
Välja en databas att ta bort från¶
Som standard kommer ett anrop för att ta bort ett befintligt objekt att utföras i samma databas som användes för att hämta objektet från första början:
>>> u = User.objects.using("legacy_users").get(username="fred")
>>> u.delete() # will delete from the `legacy_users` database
För att ange databasen från vilken en modell ska raderas, skicka ett using
nyckelordsargument till metoden Model.delete()
. Detta argument fungerar precis som nyckelordsargumentet using
till save()
.
Om du t.ex. ska flytta en användare från databasen legacy_users
till databasen new_users
kan du använda följande kommandon:
>>> user_obj.save(using="new_users")
>>> user_obj.delete(using="legacy_users")
Använda chefer med flera databaser¶
Använd metoden db_manager()
på managers för att ge managers tillgång till en databas som inte är standard.
Anta till exempel att du har en anpassad managermetod som berör databasen - User.objects.create_user()
. Eftersom create_user()
är en managermetod, inte en QuerySet
-metod, kan du inte göra User.objects.using('new_users').create_user()
. (Metoden create_user()
är endast tillgänglig på User.objects
, hanteraren, inte på QuerySet
-objekt som härrör från hanteraren) Lösningen är att använda db_manager()
, så här:
User.objects.db_manager("new_users").create_user(...)
db_manager()
returnerar en kopia av den manager som är knuten till den databas du anger.
Använda get_queryset()
med flera databaser¶
Om du åsidosätter get_queryset()
på din manager, se till att antingen anropa metoden på den överordnade (med super()
) eller gör lämplig hantering av _db
-attributet på managern (en sträng som innehåller namnet på den databas som ska användas).
Om du till exempel vill returnera en anpassad QuerySet
-klass från get_queryset
-metoden kan du göra så här:
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
Exponering av flera databaser i Djangos admin-gränssnitt¶
Djangos admin har inte något uttryckligt stöd för flera databaser. Om du vill tillhandahålla ett administratörsgränssnitt för en modell på en annan databas än den som anges av din routerkedja måste du skriva anpassade ModelAdmin
-klasser som kommer att styra administratören att använda en specifik databas för innehåll.
objekten ModelAdmin
har följande metoder som kräver anpassning för stöd för flera databaser:
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
)
Den implementering som tillhandahålls här implementerar en strategi med flera databaser där alla objekt av en viss typ lagras i en specifik databas (t.ex. alla User
-objekt finns i databasen other
). Om din användning av flera databaser är mer komplex måste din ModelAdmin
återspegla den strategin.
InlineModelAdmin
-objekt kan hanteras på ett liknande sätt. De kräver tre anpassade metoder:
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
)
När du har skrivit dina modelladministratörsdefinitioner kan de registreras med valfri Admin
-instans:
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)
I detta exempel skapas två administratörswebbplatser. På den första webbplatsen exponeras objekten Author
och Publisher
; Publisher
-objekten har en tabulär inline som visar böcker som publicerats av det förlaget. Den andra webbplatsen exponerar bara förläggare, utan inlines.
Använda råa markörer med flera databaser¶
Om du använder mer än en databas kan du använda django.db.connections
för att få anslutningen (och markören) för en specifik databas. django.db.connections
är ett ordboksliknande objekt som gör att du kan hämta en specifik anslutning med hjälp av dess alias:
from django.db import connections
with connections["my_db_alias"].cursor() as cursor:
...
Begränsningar med flera databaser¶
Relationer mellan olika databaser¶
Django ger för närvarande inget stöd för foreign key eller many-to-many-relationer som sträcker sig över flera databaser. Om du har använt en router för att partitionera modeller till olika databaser måste alla foreign key- och many-to-many-relationer som definieras av dessa modeller vara interna i en enda databas.
Detta beror på referentiell integritet. För att kunna upprätthålla en relation mellan två objekt måste Django veta att primärnyckeln för det relaterade objektet är giltig. Om primärnyckeln lagras i en separat databas är det inte möjligt att enkelt utvärdera giltigheten för en primärnyckel.
Om du använder Postgres, SQLite, Oracle eller MySQL med InnoDB verkställs detta på databasintegritetsnivå - nyckelbegränsningar på databasnivå förhindrar att relationer skapas som inte kan valideras.
Men om du använder MySQL med MyISAM-tabeller finns det ingen påtvingad referensintegritet; som ett resultat kan du kanske ”fejka” utländska nycklar i korsdatabasen. Denna konfiguration stöds dock inte officiellt av Django.
Beteende hos Contrib-appar¶
Flera Contrib-appar innehåller modeller, och vissa appar är beroende av andra. Eftersom relationer mellan databaser är omöjliga skapar detta vissa begränsningar för hur du kan dela dessa modeller mellan olika databaser:
var och en av
contenttypes.ContentType
,sessions.Session
ochsites.Site
kan lagras i vilken databas som helst, förutsatt att en lämplig router används.auth
-modellerna -User
,Group
ochPermission
- är sammanlänkade och länkade tillContentType
, så de måste lagras i samma databas somContentType
.admin
är beroende avauth
, så dess modeller måste finnas i samma databas somauth
.flatpages
ochredirects
är beroende avsites
, så deras modeller måste finnas i samma databas somsites
.
Dessutom skapas vissa objekt automatiskt strax efter att migrate
har skapat en tabell för att hålla dem i en databas:
en förvald
Site
,en
ContentType
för varje modell (även de som inte finns lagrade i databasen),”Tillstånd” för varje modell (även de som inte lagras i databasen).
För vanliga konfigurationer med flera databaser är det inte användbart att ha dessa objekt i mer än en databas. Vanliga konfigurationer inkluderar primär/replika och anslutning till externa databaser. Därför rekommenderas det att skriva en databasrouter som gör det möjligt att synkronisera dessa tre modeller till endast en databas. Använd samma tillvägagångssätt för contrib- och tredjepartsappar som inte behöver sina tabeller i flera databaser.
Varning
Om du synkroniserar innehållstyper till mer än en databas bör du vara medveten om att deras primärnycklar kanske inte stämmer överens mellan databaserna. Detta kan leda till datakorruption eller dataförlust.