Databaser¶
Django har officiellt stöd för följande databaser:
Det finns också ett antal databasbackends som tillhandahålls av tredje part.
Django försöker att stödja så många funktioner som möjligt på alla databasbackends. Alla databasbackends är dock inte likadana, och vi har varit tvungna att fatta designbeslut om vilka funktioner som ska stödjas och vilka antaganden vi kan göra på ett säkert sätt.
Den här filen beskriver några av de funktioner som kan vara relevanta för Django-användning. Den är inte avsedd att ersätta serverspecifik dokumentation eller referenshandböcker.
Allmänna anteckningar¶
Beständiga anslutningar¶
Med beständiga anslutningar undviks omkostnaderna för att återupprätta en anslutning till databasen vid varje HTTP-begäran. De styrs av parametern CONN_MAX_AGE
som definierar den maximala livslängden för en anslutning. Den kan ställas in oberoende för varje databas.
Standardvärdet är 0
, vilket bevarar det historiska beteendet att stänga databasanslutningen i slutet av varje begäran. För att aktivera långvariga anslutningar, ställ in CONN_MAX_AGE
till ett positivt heltal av sekunder. För obegränsade långvariga anslutningar, ställ in den på None
.
När ASGI används bör permanenta anslutningar inaktiveras. Använd istället databasens inbyggda anslutningspoolning om den finns tillgänglig, eller undersök ett alternativ för anslutningspoolning från tredje part om det behövs.
Hantering av anslutningar¶
Django öppnar en anslutning till databasen när den först gör en databasförfrågan. Den håller denna anslutning öppen och återanvänder den i efterföljande förfrågningar. Django stänger anslutningen när den överskrider den maximala ålder som definieras av CONN_MAX_AGE
eller när den inte längre kan användas.
I detalj öppnar Django automatiskt en anslutning till databasen när den behöver en och inte redan har en - antingen för att detta är den första anslutningen eller för att den tidigare anslutningen stängdes.
I början av varje begäran stänger Django anslutningen om den har nått sin maximala ålder. Om din databas avslutar inaktiva anslutningar efter en viss tid bör du ställa in CONN_MAX_AGE
till ett lägre värde, så att Django inte försöker använda en anslutning som har avslutats av databasservern. (Detta problem kan endast påverka webbplatser med mycket låg trafik)
I slutet av varje begäran stänger Django anslutningen om den har nått sin maximala ålder eller om den befinner sig i ett feltillstånd som inte kan återställas. Om några databasfel har inträffat under behandlingen av begärandena kontrollerar Django om anslutningen fortfarande fungerar och stänger den om den inte gör det. Databasfel påverkar således högst en begäran per varje applikations arbetstråd; om anslutningen blir oanvändbar får nästa begäran en ny anslutning.
Om du sätter CONN_HEALTH_CHECKS
till True
kan du förbättra robustheten för återanvändning av anslutningar och förhindra fel när en anslutning har stängts av databasservern som nu är redo att ta emot och hantera nya anslutningar, t.ex. efter omstart av databasservern. Hälsokontrollen utförs endast en gång per begäran och endast om databasen nås under hanteringen av begäran.
Förbehåll¶
Eftersom varje tråd upprätthåller sin egen anslutning måste din databas stödja minst lika många samtidiga anslutningar som du har arbetstrådar.
Ibland kommer majoriteten av dina vyer inte åt en databas, t.ex. för att det är databasen för ett externt system eller tack vare cachning. I sådana fall bör du ställa in CONN_MAX_AGE
till ett lågt värde eller till och med 0
, eftersom det inte är meningsfullt att upprätthålla en anslutning som sannolikt inte kommer att återanvändas. Detta bidrar till att hålla nere antalet samtidiga anslutningar till databasen.
Utvecklingsservern skapar en ny tråd för varje begäran som den hanterar, vilket upphäver effekten av beständiga anslutningar. Aktivera dem inte under utveckling.
När Django upprättar en anslutning till databasen ställer den in lämpliga parametrar, beroende på vilken backend som används. Om du aktiverar beständiga anslutningar upprepas inte längre denna inställning vid varje begäran. Om du ändrar parametrar som anslutningens isoleringsnivå eller tidszon, bör du antingen återställa Djangos standardvärden i slutet av varje begäran, tvinga fram ett lämpligt värde i början av varje begäran eller inaktivera beständiga anslutningar.
Om en anslutning skapas i en långvarig process, utanför Djangos request-response-cykel, kommer anslutningen att förbli öppen tills den uttryckligen stängs eller timeout inträffar. Du kan använda django.db.close_old_connections()
för att stänga alla gamla eller oanvändbara anslutningar.
Avkodning¶
Django förutsätter att alla databaser använder UTF-8-kodning. Om du använder andra kodningar kan det leda till oväntat beteende, till exempel ”värdet är för långt”-fel från din databas för data som är giltiga i Django. Se de databasspecifika anmärkningarna nedan för information om hur du konfigurerar din databas korrekt.
PostgreSQL anteckningar¶
Django stöder PostgreSQL 14 och högre. psycopg 3.1.8+ eller psycopg2 2.8.4+ krävs, men den senaste psycopg 3.1.8+ rekommenderas.
Observera
Stöd för psycopg2
kommer sannolikt att bli föråldrat och tas bort någon gång i framtiden.
PostgreSQL-anslutningsinställningar¶
Se HOST
för mer information.
Om du vill ansluta med ett servicenamn från connection service file och ett lösenord från password file måste du ange dem i OPTIONS
-delen av din databaskonfiguration i DATABASES
:
`ettings.py`
¶DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"OPTIONS": {
"service": "my_service",
"passfile": ".my_pgpass",
},
}
}
.pg_service.conf
¶[my_service]
host=localhost
user=USER
dbname=NAME
port=5432
.my_pgpass
¶localhost:5432:NAME:USER:PASSWORD
PostgreSQL-backend skickar innehållet i OPTIONS
som nyckelordsargument till anslutningskonstruktören, vilket möjliggör mer avancerad kontroll av drivrutinsbeteendet. Alla tillgängliga parametrar beskrivs i detalj i PostgreSQL-dokumentationen.
Varning
Att använda ett servicenamn för teständamål stöds inte. Denna kan komma att implementeras senare.
Optimera PostgreSQL: s konfiguration¶
Django behöver följande parametrar för sina databasanslutningar:
client_encoding
:'UTF8'
,default_transaction_isolation
:'read committed'
som standard, eller det värde som anges i anslutningsalternativen (se nedan),
Om dessa parametrar redan har rätt värden kommer Django inte att ställa in dem för varje ny anslutning, vilket förbättrar prestandan något. Du kan konfigurera dem direkt i postgresql.conf
eller mer bekvämt per databasanvändare med ALTER ROLE.
Django fungerar bra utan denna optimering, men varje ny anslutning kommer att göra några ytterligare frågor för att ställa in dessa parametrar.
Isolationsnivå¶
Liksom PostgreSQL själv, är Django standard för READ COMMITTED
isoleringsnivå`_. Om du behöver en högre isoleringsnivå, till exempel ``REPEATABLE READ
eller SERIALIZABLE
, ställer du in den i OPTIONS
-delen av din databaskonfiguration i DATABASES
:
from django.db.backends.postgresql.psycopg_any import IsolationLevel
DATABASES = {
# ...
"OPTIONS": {
"isolation_level": IsolationLevel.SERIALIZABLE,
},
}
Observera
Vid högre isoleringsnivåer bör ditt program vara förberett på att hantera undantag som uppstår vid serialiseringsfel. Det här alternativet är avsett för avancerad användning.
Roll¶
Om du behöver använda en annan roll för databasanslutningar än den roll som används för att upprätta anslutningen, anger du den i OPTIONS
-delen av din databaskonfiguration i DATABASES
:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ...
"OPTIONS": {
"assume_role": "my_application_role",
},
},
}
Anslutningspool¶
För att använda en anslutningspool med psycopg kan du antingen ställa in "pool"
i OPTIONS
-delen av din databaskonfiguration i DATABASER
till att vara en dict som ska skickas till ConnectionPool
, eller till True
för att använda ConnectionPool
-standardvärdena:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ...
"OPTIONS": {
"pool": True,
},
},
}
Detta alternativ kräver att psycopg[pool]
eller psycopg-pool är installerat och ignoreras med psycopg2
.
Bindning av parametrar på serversidan¶
Med psycopg 3.1.8+ använder Django som standard :ref:``client-side binding cursors <psycopg:client-side-binding-cursors>`. Om du vill använda :ref:``server-side binding <psycopg:server-side-binding>` ställ in det i OPTIONS
-delen av din databaskonfiguration i DATABASES
:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
# ...
"OPTIONS": {
"server_side_binding": True,
},
},
}
Detta alternativ ignoreras med psycopg2
.
Index för kolumnerna varchar
och text
¶
När du anger db_index=True
på dina modellfält, skriver Django vanligtvis ut ett enda CREATE INDEX
-uttalande. Men om databastypen för fältet är antingen varchar
eller text
(t.ex. används av CharField
, FileField
och TextField
), kommer Django att skapa ett extra index som använder en lämplig PostgreSQL-operatörsklass för kolumnen. Det extra indexet är nödvändigt för att korrekt utföra uppslagningar som använder operatören LIKE
i sin SQL, vilket görs med uppslagningstyperna contains
och startswith
.
Migrationsoperation för att lägga till tillägg¶
Om du behöver lägga till en PostgreSQL-förlängning (som hstore
, postgis
, etc.) med hjälp av en migrering, använd CreateExtension
operation.
Markörer på serversidan¶
När du använder QuerySet.iterator()
öppnar Django en server-side cursor. Som standard antar PostgreSQL att endast de första 10% of resultaten av markörfrågor kommer att hämtas. Frågeplaneraren spenderar mindre tid på att planera frågan och börjar returnera resultat snabbare, men detta kan minska prestandan om mer än 10% of resultaten hämtas. PostgreSQL: s antaganden om antalet rader som hämtas för en markörfråga styrs med alternativet cursor_tuple_fraction.
Transaktionspoolning och cursorer på serversidan¶
Om du använder en anslutningspooler i transaktionspoolningsläge (t.ex. PgBouncer) måste du inaktivera markörer på serversidan för den anslutningen.
Markörer på serversidan är lokala för en anslutning och förblir öppna i slutet av en transaktion när :setting:AUTOCOMMIT <DATABASE-AUTOCOMMIT>
är True
. En efterföljande transaktion kan försöka hämta fler resultat från en markör på serversidan. I transaktionspoolningsläget finns det ingen garanti för att efterföljande transaktioner kommer att använda samma anslutning. Om en annan anslutning används uppstår ett fel när transaktionen refererar till markören på serversidan, eftersom markörer på serversidan endast är tillgängliga i den anslutning där de skapades.
En lösning är att inaktivera markörer på serversidan för en anslutning i DATABASER
genom att ställa in DISABLE_SERVER_SIDE_CURSORS
till True
.
Om du vill dra nytta av markörer på serversidan i transaktionspoolningsläge kan du konfigurera en annan anslutning till databasen för att utföra frågor som använder markörer på serversidan. Den här anslutningen måste antingen vara direkt till databasen eller till en anslutningspooler i sessionspoolningsläge.
Ett annat alternativ är att linda in varje QuerySet
som använder markörer på serversidan i ett atomic()
-block, eftersom det inaktiverar autocommit
under transaktionens varaktighet. På så sätt kommer markören på serversidan bara att leva under transaktionens varaktighet.
Manuellt specificerade värden för primärnycklar med automatisk inkrementering¶
Django använder PostgreSQLs identitetskolumner för att lagra automatiskt ökande primärnycklar. En identitetskolumn fylls med värden från en sekvens som håller reda på nästa tillgängliga värde. Att manuellt tilldela ett värde till ett fält med automatisk ökning uppdaterar inte fältets sekvens, vilket senare kan orsaka en konflikt. Ett exempel:
>>> from django.contrib.auth.models import User
>>> User.objects.create(username="alice", pk=1)
<User: alice>
>>> # The sequence hasn't been updated; its next value is 1.
>>> User.objects.create(username="bob")
IntegrityError: duplicate key value violates unique constraint
"auth_user_pkey" DETAIL: Key (id)=(1) already exists.
Om du behöver ange sådana värden ska du återställa sekvensen efteråt för att undvika att återanvända ett värde som redan finns i tabellen. Hanteringskommandot sqlsequencereset
genererar SQL-satserna för att göra detta.
Test av databasmallar¶
Du kan använda inställningen TEST['TEMPLATE']
för att ange en template (t.ex. 'template0'
) från vilken en testdatabas ska skapas.
Snabbare testkörning med icke-durabla inställningar¶
Du kan påskynda testkörningstiderna genom att konfigurera PostgreSQL för att vara icke-durable.
Varning
Detta är farligt: det gör din databas mer mottaglig för dataförlust eller korruption i händelse av en serverkrasch eller strömavbrott. Använd detta endast på en utvecklingsmaskin där du enkelt kan återställa hela innehållet i alla databaser i klustret.
MariaDB anteckningar¶
Django stöder MariaDB 10.5 och senare.
För att använda MariaDB, använd MySQL-backend, som delas mellan de två. Se MySQL notes för mer information.
Anteckningar om MySQL¶
Stöd för version¶
Django stöder MySQL 8.0.11 och senare.
Djangos funktion inspectdb
använder databasen information_schema
, som innehåller detaljerade uppgifter om alla databasscheman.
Django förväntar sig att databasen stöder Unicode (UTF-8-kodning) och delegerar till den uppgiften att upprätthålla transaktioner och referensintegritet. Det är viktigt att vara medveten om det faktum att de två sistnämnda faktiskt inte upprätthålls av MySQL när MyISAM-lagringsmotorn används, se nästa avsnitt.
Lagringsmotorer¶
MySQL har flera lagringsmotorer. Du kan ändra standardlagringsmotorn i serverkonfigurationen.
MySQL:s standardlagringsmotor är InnoDB. Denna motor är helt transaktionell och stöder utländska nyckelreferenser. Det är det rekommenderade valet. InnoDB:s autoincrement-räknare går dock förlorad vid en MySQL-omstart eftersom den inte kommer ihåg värdet AUTO_INCREMENT
, utan istället återskapar det som ”max(id)+1”. Detta kan resultera i en oavsiktlig återanvändning av AutoField
-värden.
De största nackdelarna med MyISAM är att den inte stöder transaktioner eller upprätthåller begränsningar för utländska nycklar.
MySQL DB API-drivrutiner¶
MySQL har ett par drivrutiner som implementerar Python Database API som beskrivs i PEP 249:
mysqlclient är en inbyggd drivrutin. Det är det rekommenderade valet.
MySQL Connector/Python är en ren Python-drivrutin från Oracle som inte kräver MySQL-klientbiblioteket eller några Python-moduler utanför standardbiblioteket.
Förutom en DB API-drivrutin behöver Django en adapter för att komma åt databasdrivrutinerna från sin ORM. Django tillhandahåller en adapter för mysqlclient medan MySQL Connector/Python innehåller sin egen.
mysqlclient¶
Django kräver mysqlclient 1.4.3 eller senare.
MySQL Connector/Python¶
MySQL Connector/Python är tillgänglig från nedladdningssidan. Django-adaptern är tillgänglig i version 1.1.X och senare. Den kanske inte stöder de senaste versionerna av Django.
Definitioner av tidszoner¶
Om du planerar att använda Djangos tidszonsstöd, använd mysql_tzinfo_to_sql för att ladda tidszonstabeller i MySQL-databasen. Detta behöver bara göras en gång för din MySQL-server, inte per databas.
Skapa din databas¶
Du kan skapa din databas med hjälp av kommandoradsverktygen och denna SQL:
CREATE DATABASE <dbname> CHARACTER SET utf8mb4;
Detta säkerställer att alla tabeller och kolumner använder UTF-8 som standard.
Inställningar för sortering¶
Kollationsinställningen för en kolumn styr den ordning i vilken data sorteras samt vilka strängar som jämförs som lika. Du kan ange parametern db_collation
för att ställa in kolumnens kollationsnamn för CharField
och TextField
.
Kollationen kan också ställas in på en databasomfattande nivå och per tabell. Detta är dokumenterat grundligt i MySQL-dokumentationen. I sådana fall måste du ställa in sorteringen genom att direkt manipulera databasinställningarna eller tabellerna. Django tillhandahåller inte ett API för att ändra dem.
Som standard, med en UTF-8-databas, kommer MySQL att använda kollationen utf8mb4_0900_ai_ci
. Detta resulterar i att alla jämförelser av stränglikhet görs på ett case-insensitive sätt. Det innebär att "Fred"
och "freD"
betraktas som lika på databasnivå. Om du har en unik begränsning på ett fält skulle det vara olagligt att försöka infoga både "aa"
och "AA"
i samma kolumn, eftersom de jämförs som lika (och därmed icke-unika) med standardkollationen. Om du vill ha jämförelser med skiftlägeskänslighet i en viss kolumn eller tabell, ändrar du kolumnen eller tabellen så att den använder sorteringen utf8mb4_0900_as_cs
.
Observera att enligt MySQL Unicode Character Sets är jämförelser för `` utf8mb4_general_ci`` kollation snabbare, men något mindre korrekta än jämförelser för `` utf8mb4_unicode_ci``. Om detta är acceptabelt för ditt program bör du använda utf8mb4_general_ci
eftersom det är snabbare. Om detta inte är acceptabelt (t.ex. om du behöver tysk ordboksordning), använd utf8mb4_unicode_ci
eftersom det är mer exakt.
Varning
Modellformulären validerar unika fält på ett skiftlägeskänsligt sätt. Om man använder en kollationering som inte tar hänsyn till versaler kommer en formuläruppsättning med unika fältvärden som endast skiljer sig åt genom versaler att klara valideringen, men när man anropar save()
kommer ett IntegrityError
att uppstå.
Anslutning till databasen¶
Anslutningsinställningarna används i denna ordning:
Med andra ord, om du anger namnet på databasen i OPTIONS
, kommer detta att ha företräde framför NAME
, som skulle åsidosätta allt i en MySQL-alternativfil.
Här är ett exempel på en konfiguration som använder en MySQL-alternativfil:
# settings.py
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"OPTIONS": {
"read_default_file": "/path/to/my.cnf",
},
}
}
# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8mb4
Flera andra MySQLdb-anslutningsalternativ kan vara användbara, till exempel ssl
, init_command
och sql_mode
.
Ställa in sql_mode
¶
Standardvärdet för alternativet sql_mode
innehåller STRICT_TRANS_TABLES
. Det alternativet eskalerar varningar till fel när data trunkeras vid infogning, så Django rekommenderar starkt att du aktiverar ett strikt läge för MySQL för att förhindra dataförlust (antingen STRICT_TRANS_TABLES
eller STRICT_ALL_TABLES
).
Om du behöver anpassa SQL-läget kan du ställa in variabeln sql_mode
som andra MySQL-alternativ: antingen i en konfigurationsfil eller med posten 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"
i OPTIONS
-delen av din databaskonfiguration i DATABASER
.
Isolationsnivå¶
När samtidiga belastningar körs kan databastransaktioner från olika sessioner (t.ex. separata trådar som hanterar olika förfrågningar) interagera med varandra. Dessa interaktioner påverkas av varje sessions transaktionsisoleringsnivå. Du kan ange en anslutnings isoleringsnivå med en 'isolation_level'
-post i OPTIONS
-delen av din databaskonfiguration i DATABASER
. Giltiga värden för den här posten är de fyra standardisoleringsnivåerna:
'läsa utan åtagande'
`läs engagerad
”upprepningsbar läsning
'serialiserbar'`
eller None
för att använda serverns konfigurerade isoleringsnivå. Django fungerar dock bäst med och använder som standard read committed i stället för MySQL:s standard, repeatable read. Dataförlust är möjlig med repeterbar läsning. I synnerhet kan du se fall där get_or_create()
kommer att ge upphov till ett IntegrityError
men objektet kommer inte att visas i ett efterföljande get()
-anrop.
Skapa dina tabeller¶
När Django genererar schemat anges ingen lagringsmotor, så tabeller kommer att skapas med den standardlagringsmotor som din databasserver är konfigurerad för. Den enklaste lösningen är att ställa in din databasservers standardlagringsmotor till den önskade motorn.
Om du använder en värdtjänst och inte kan ändra serverns standardlagringsmotor har du ett par alternativ.
När tabellerna har skapats kan du köra en
ALTER TABLE
-sats för att konvertera en tabell till en ny lagringsmotor (t.ex. InnoDB):ALTER TABLE <tablename> ENGINE=INNODB;
Detta kan vara tråkigt om du har många tabeller.
Ett annat alternativ är att använda alternativet
init_command
för MySQLdb innan du skapar dina tabeller:"OPTIONS": { "init_command": "SET default_storage_engine=INNODB", }
Detta anger standardlagringsmotorn vid anslutning till databasen. När tabellerna har skapats bör du ta bort det här alternativet eftersom det lägger till en fråga som bara behövs när tabellerna skapas i varje databasanslutning.
Tabellnamn¶
Det finns kända problem även i de senaste versionerna av MySQL som kan leda till att versalerna i ett tabellnamn ändras när vissa SQL-satser körs under vissa förhållanden. Det rekommenderas att du använder små bokstäver i tabellnamn, om möjligt, för att undvika problem som kan uppstå på grund av detta beteende. Django använder små bokstäver i tabellnamn när det automatiskt genererar tabellnamn från modeller, så detta är främst ett övervägande om du åsidosätter tabellnamnet via db_table
-parametern.
Spara poäng¶
Både Django ORM och MySQL (när de använder InnoDB storage engine) stöder databas savepoints.
Om du använder MyISAM-lagringsmotorn bör du vara medveten om att du kommer att få databasgenererade fel om du försöker använda savepoint-relaterade metoder i transaktions-API:n. Anledningen till detta är att det är en dyr operation att upptäcka lagringsmotorn för en MySQL-databas/tabell, så det beslutades att det inte är värt att dynamiskt konvertera dessa metoder till no-op baserat på resultaten av sådan upptäckt.
Anteckningar om specifika områden¶
Teckenfält¶
Alla fält som lagras med kolumntyperna VARCHAR
kan ha sin max_length
begränsad till 255 tecken om du använder unique=True
för fältet. Detta påverkar CharField
, SlugField
. Se MySQL-dokumentationen för mer information.
begränsningar för TextField
¶
MySQL kan endast indexera de första N tecknen i en BLOB
eller TEXT
-kolumn. Eftersom TextField
inte har en definierad längd kan du inte markera den som unique=True
. MySQL kommer att rapportera: ”BLOB/TEXT-kolumn ’<db_column>’ används i nyckelspecifikation utan en nyckellängd”.
Stöd för bråkdelar av sekunder för Time- och DateTime-fält¶
MySQL kan lagra bråkdelar av sekunder, förutsatt att kolumndefinitionen innehåller en bråkdelsindikation (t.ex. DATETIME(6)
).
Django kommer inte att uppgradera befintliga kolumner för att inkludera bråkdelar av sekunder om databasservern stöder det. Om du vill aktivera dem i en befintlig databas är det upp till dig att antingen manuellt uppdatera kolumnen i måldatabasen genom att köra ett kommando som:
ALTER TABLE `your_table` MODIFY `your_datetime_column` DATETIME(6)
eller använda en RunSQL
operation i en datamigrering.
TIMESTAMP
kolumner¶
Om du använder en äldre databas som innehåller TIMESTAMP
-kolumner måste du ställa in USE_TZ = False
för att undvika datakorruption. inspectdb
mappar dessa kolumner till DateTimeField
och om du aktiverar tidszonsstöd kommer både MySQL och Django att försöka konvertera värdena från UTC till lokal tid.
Radlåsning med QuerySet.select_for_update()
¶
MySQL och MariaDB stöder inte vissa alternativ till SELECT ... FOR UPDATE
-satsen. Om select_for_update()
används med ett alternativ som inte stöds, kommer ett NotSupportedError
att uppstå.
Alternativ |
MariaDB |
MySQL |
---|---|---|
|
X (≥10.6) |
X |
|
X |
X |
|
X |
|
|
När du använder select_for_update()
på MySQL, se till att du filtrerar en frågeuppsättning mot åtminstone en uppsättning fält som ingår i unika begränsningar eller endast mot fält som täcks av index. Annars kommer ett exklusivt skrivlås att förvärvas över hela tabellen under hela transaktionens varaktighet.
Automatisk typcasting kan leda till oväntade resultat¶
När du utför en fråga på en strängtyp, men med ett heltalsvärde, kommer MySQL att tvinga typerna för alla värden i tabellen till ett heltal innan jämförelsen utförs. Om din tabell innehåller värdena 'abc'
, 'def'
och du frågar efter WHERE mycolumn=0
, kommer båda raderna att matcha. På samma sätt kommer WHERE mycolumn=1
att matcha värdet 'abc1'
. Därför kommer fält av strängtyp som ingår i Django alltid att kasta värdet till en sträng innan det används i en fråga.
Om du implementerar anpassade modellfält som ärver från Field
direkt, åsidosätter get_prep_value()
eller använder RawSQL
, extra()
, eller raw()
, bör du se till att du utför lämplig typecasting.
Anteckningar om SQLite¶
Django stöder SQLite 3.31.0 och senare.
SQLite är ett utmärkt utvecklingsalternativ för applikationer som huvudsakligen är skrivskyddade eller som kräver en mindre installation. Som med alla databasservrar finns det dock vissa skillnader som är specifika för SQLite som du bör vara medveten om.
Matchning av substrängar och skiftlägeskänslighet¶
För alla SQLite-versioner finns det ett något kontraintuitivt beteende när man försöker matcha vissa typer av strängar. Dessa utlöses när man använder filtren iexact
eller contains
i frågeuppsättningar. Beteendet delas upp i två fall:
1. For substring matching, all matches are done case-insensitively. That is a
filter such as filter(name__contains="aa")
will match a name of "Aabb"
.
2. For strings containing characters outside the ASCII range, all exact string
matches are performed case-sensitively, even when the case-insensitive options
are passed into the query. So the iexact
filter will behave exactly
the same as the exact
filter in these cases.
Några möjliga lösningar för detta finns dokumenterade på sqlite.org, men de används inte av standard SQLite-backend i Django, eftersom det skulle vara ganska svårt att göra dem robusta. Således exponerar Django standard SQLite-beteendet och du bör vara medveten om detta när du gör skiftlägeskänslig eller delsträngsfiltrering.
Decimalhantering¶
SQLite har ingen riktig decimal intern typ. Decimalvärden konverteras internt till datatypen REAL
(8-byte IEEE flyttalsnummer), vilket förklaras i SQLite datatypes documentation, så de stöder inte korrekt avrundad decimal flyttalsaritmetik.
felmeddelandet ”Databasen är låst”¶
SQLite är tänkt att vara en lättviktig databas och kan därför inte stödja en hög nivå av samtidighet. OperationalError: database is locked
-fel indikerar att din applikation upplever mer samtidighet än vad sqlite
kan hantera i standardkonfigurationen. Det här felet innebär att en tråd eller process har ett exklusivt lås på databasanslutningen och att en annan tråd tidsavbröts i väntan på att låset skulle frigöras.
Pythons SQLite-wrapper har ett standardvärde för timeout som avgör hur länge den andra tråden får vänta på låset innan det tar slut och felet OperationalError: database is locked
uppstår.
Om du får det här felet kan du lösa det genom att:
Byta till en annan databasbackend. Vid en viss punkt blir SQLite för ”lite” för verkliga applikationer, och den här typen av samtidighetsfel indikerar att du har nått den punkten.
Skriva om din kod för att minska samtidighet och säkerställa att databastransaktioner är kortlivade.
Öka standardvärdet för timeout genom att ställa in databasalternativet
timeout
:"OPTIONS": { # ... "timeout": 20, # ... }
Detta gör att SQLite väntar lite längre innan den ger felmeddelandet ”databasen är låst”, men det gör egentligen ingenting för att lösa dem.
Transaktionsbeteende¶
SQLite stöder tre transaktionslägen: DEFERRED
, IMMEDIATE
och EXCLUSIVE
.
Standardvärdet är DEFERRED
. Om du behöver använda ett annat läge anger du det i OPTIONS
-delen av din databaskonfiguration i DATABASER
, till exempel:
"OPTIONS": {
# ...
"transaction_mode": "IMMEDIATE",
# ...
}
Om du vill vara säker på att dina transaktioner väntar till timeout
innan du meddelar ”Databasen är låst”, ändrar du transaktionsläget till IMMEDIATE
.
För bästa prestanda med IMMEDIATE
och EXCLUSIVE
bör transaktionerna vara så korta som möjligt. Detta kan vara svårt att garantera för alla dina vyer, så användningen av ATOMIC_REQUESTS
avråds i detta fall.
För mer information se Transaktioner i SQLite.
QuerySet.select_for_update()
stöds inte¶
SQLite har inte stöd för syntaxen SELECT ... FOR UPDATE
. Att anropa den kommer inte att ha någon effekt.
Isolering vid användning av QuerySet.iterator()
¶
Det finns särskilda överväganden som beskrivs i Isolation In SQLite när man ändrar en tabell medan man itererar över den med QuerySet.iterator()
. Om en rad läggs till, ändras eller tas bort inom loopen kan den raden visas eller inte visas, eller visas två gånger, i efterföljande resultat som hämtas från iteratorn. Din kod måste hantera detta.
Aktivera JSON1-tillägget på SQLite¶
För att använda JSONField
på SQLite måste du aktivera JSON1-tillägget på Pythons sqlite3
-bibliotek. Om tillägget inte är aktiverat i din installation kommer ett systemfel (fields.E180
) att uppstå.
För att aktivera JSON1-tillägget kan du följa instruktionerna på wikisidan.
Observera
JSON1-tillägget är aktiverat som standard i SQLite 3.38+.
Ställa in pragma-alternativ¶
Pragma options kan ställas in vid anslutning med hjälp av init_command
i OPTIONS
-delen av din databaskonfiguration i DATABASES
. I exemplet nedan visas hur man aktiverar extra hållbarhet för synkrona skrivningar och ändrar cache_size
:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
# ...
"OPTIONS": {
"init_command": "PRAGMA synchronous=3; PRAGMA cache_size=2000;",
},
}
}
Oracle anteckningar¶
Django stöder Oracle Database Server version 19c och senare. Version 2.3.0 eller högre av Python-drivrutinen oracledb krävs.
Deprecated since version 5.0: Stöd för cx_Oracle
är borttaget.
För att kommandot python manage.py migrate
ska fungera måste din Oracle-databasanvändare ha behörighet att köra följande kommandon:
SKAPA TABELL
SKAPA SEKVENS
SKAPA PROCEDUR
SKAPA TRIGGER
För att köra ett projekts testsvit behöver användaren vanligtvis dessa ytterligare behörigheter:
SKAPA ANVÄNDARE
ÄNDRAR ANVÄNDARE
DROP ANVÄNDARE
SKAPA TABLESPACE
SLÄPP TABLESPACE
SKAPA SESSION MED ADMINISTRATÖRSALTERNATIV
SKAPA TABELL MED ADMINISTRATÖRSALTERNATIV
SKAPA SEKVENS MED ADMINISTRATÖRSALTERNATIV
SKAPA PROCEDUR MED ADMINISTRATÖRSALTERNATIV
SKAPA TRIGGER MED ADMINISTRATÖRSALTERNATIV
Även om rollen RESOURCE
har de nödvändiga behörigheterna CREATE TABLE
, CREATE SEQUENCE
, CREATE PROCEDURE
och CREATE TRIGGER
och en användare som tilldelats RESOURCE WITH ADMIN OPTION
kan tilldela RESOURCE
, kan en sådan användare inte tilldela de enskilda behörigheterna (t.ex.t.ex. CREATE TABLE
), och därför är RESOURCE WITH ADMIN OPTION
vanligtvis inte tillräckligt för att köra tester.
Vissa testsviter skapar också vyer eller materialiserade vyer; för att köra dessa behöver användaren också behörigheterna CREATE VIEW WITH ADMIN OPTION
och CREATE MATERIALIZED VIEW WITH ADMIN OPTION
. I synnerhet behövs detta för Djangos egen testsvit.
Alla dessa behörigheter ingår i DBA-rollen, som är lämplig att använda i en privat utvecklares databas.
Oracle-databasens backend använder paketen SYS.DBMS_LOB
och SYS.DBMS_RANDOM
, så din användare kommer att behöva exekveringsbehörighet för det. Det är normalt tillgängligt för alla användare som standard, men om det inte är det måste du ge behörigheter på följande sätt:
GRANT EXECUTE ON SYS.DBMS_LOB TO user;
GRANT EXECUTE ON SYS.DBMS_RANDOM TO user;
Anslutning till databasen¶
Om du vill ansluta med hjälp av servicenamnet för din Oracle-databas ska filen settings.py
se ut ungefär så här:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.oracle",
"NAME": "xe",
"USER": "a_user",
"PASSWORD": "a_password",
"HOST": "",
"PORT": "",
}
}
I det här fallet bör du lämna både HOST
och PORT
tomma. Om du däremot inte använder filen tnsnames.ora
eller någon liknande namngivningsmetod och vill ansluta med hjälp av SID (”xe” i det här exemplet), fyller du i både HOST
och PORT
på följande sätt:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.oracle",
"NAME": "xe",
"USER": "a_user",
"PASSWORD": "a_password",
"HOST": "dbprod01ned.mycompany.com",
"PORT": "1540",
}
}
Du bör antingen ange både HOST
och PORT
, eller lämna båda som tomma strängar. Django kommer att använda en annan connect descriptor beroende på detta val.
Fullständig DSN och Easy Connect¶
En fullständig DSN- eller Easy Connect-sträng kan användas i NAME
om både HOST
och PORT
är tomma. Det här formatet krävs när du använder RAC eller pluggbara databaser utan tnsnames.ora
, till exempel.
Exempel på en Easy Connect-sträng:
"NAME": "localhost:1521/orclpdb1"
Exempel på en fullständig DSN-sträng:
"NAME": (
"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
"(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))"
)
Anslutningspool¶
För att använda en anslutningspool med oracledb, sätt "pool"
till True
i OPTIONS
-delen av din databaskonfiguration. Detta använder drivrutinens create_pool() standardvärden:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.oracle",
# ...
"OPTIONS": {
"pool": True,
},
},
}
För att skicka anpassade parametrar till drivrutinens funktion create_pool() kan du alternativt ange att "pool"
ska vara en dict:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.oracle",
# ...
"OPTIONS": {
"pool": {
"min": 1,
"max": 10,
# ...
}
},
},
}
Gängat alternativ¶
Om du planerar att köra Django i en flertrådad miljö (t.ex. Apache med standardmodulen MPM på alla moderna operativsystem), måste du ** ställa in alternativet threaded
i din Oracle-databas konfiguration till True
:
"OPTIONS": {
"threaded": True,
}
Om du inte gör detta kan det leda till krascher och andra konstiga beteenden.
INFOGA … ÅTERVÄNDANDE TILL¶
Som standard använder Oracle backend en ”RETURNING INTO”-klausul för att effektivt hämta värdet på en ”AutoField” när nya rader infogas. Detta beteende kan resultera i ett DatabaseError
i vissa ovanliga konfigurationer, t.ex. när du infogar i en fjärrtabell eller i en vy med en INSTEAD OF
-trigger. Klausulen RETURNING INTO
kan inaktiveras genom att alternativet use_returning_into
i databaskonfigurationen sätts till False
:
"OPTIONS": {
"use_returning_into": False,
}
I det här fallet kommer Oracle-backend att använda en separat SELECT
-fråga för att hämta AutoField
-värden.
Problem med namngivning¶
Oracle har en begränsning på 30 tecken för namnlängden. För att tillgodose detta trunkerar backend databasidentifierare så att de passar och ersätter de sista fyra tecknen i det trunkerade namnet med ett upprepningsbart MD5-hashvärde. Dessutom ändrar backend databasidentifierare till enbart versaler.
För att förhindra dessa omvandlingar (detta krävs vanligtvis endast när man arbetar med äldre databaser eller har åtkomst till tabeller som tillhör andra användare), använd ett citerat namn som värde för db_table
:
class LegacyModel(models.Model):
class Meta:
db_table = '"name_left_in_lowercase"'
class ForeignModel(models.Model):
class Meta:
db_table = '"OTHER_USER"."NAME_ONLY_SEEMS_OVER_30"'
Citerade namn kan också användas med Djangos andra stödda databasbackends; med undantag för Oracle har citaten dock ingen effekt.
När man kör migrate
kan felet ORA-06552
uppstå om vissa Oracle-nyckelord används som namn på ett modellfält eller som värde på ett db_column
-alternativ. Django citerar alla identifierare som används i frågor för att förhindra de flesta sådana problem, men det här felet kan fortfarande uppstå när en Oracle-datatyp används som ett kolumnnamn. Var särskilt noga med att undvika att använda namnen date
, timestamp
, number
eller float
som fältnamn.
NULL och tomma strängar¶
Django föredrar i allmänhet att använda den tomma strängen (''
) i stället för NULL
, men Oracle behandlar båda identiskt. För att komma runt detta ignorerar Oracle-backend ett explicit null
-alternativ på fält som har den tomma strängen som ett möjligt värde och genererar DDL som om null=True
. Vid hämtning från databasen antas det att ett NULL
-värde i ett av dessa fält verkligen betyder den tomma strängen, och data konverteras tyst för att återspegla detta antagande.
begränsningar för TextField
¶
Oracles backend lagrar varje TextField
som en NCLOB
-kolumn. Oracle inför vissa begränsningar för användningen av sådana LOB-kolumner i allmänhet:
LOB-kolumner får inte användas som primärnycklar.
LOB-kolumner får inte användas i index.
LOB-kolumner får inte användas i en
SELECT DISTINCT
-lista. Detta innebär att försök att använda metodenQuerySet.distinct
på en modell som innehållerTextField
-kolumner kommer att resultera i ettORA-00932
-fel när den körs mot Oracle. Som en lösning kan du använda metodenQuerySet.defer
tillsammans meddistinct()
för att förhindra attTextField
-kolumner inkluderas i listanSELECT DISTINCT
.
Underklassning av de inbyggda databasbackends¶
Django levereras med inbyggda databasbackends. Du kan underklassa en befintlig databasbackend för att ändra dess beteende, funktioner eller konfiguration.
Tänk dig till exempel att du behöver ändra en enda databasfunktion. Först måste du skapa en ny katalog med en base
-modul i den. Ett exempel:
mysite/
...
mydbengine/
__init__.py
base.py
Modulen base.py
måste innehålla en klass med namnet DatabaseWrapper
som underklassar en befintlig motor från modulen django.db.backends
. Här är ett exempel på underklassning av PostgreSQL-motorn för att ändra en funktionsklass allows_group_by_selected_pks_on_model
:
mysite/mydbengine/base.py
¶from django.db.backends.postgresql import base, features
class DatabaseFeatures(features.DatabaseFeatures):
def allows_group_by_selected_pks_on_model(self, model):
return True
class DatabaseWrapper(base.DatabaseWrapper):
features_class = DatabaseFeatures
Slutligen måste du ange en DATABASE-ENGINE
i din settings.py
-fil:
DATABASES = {
"default": {
"ENGINE": "mydbengine",
# ...
},
}
Du kan se den aktuella listan över databasmotorer genom att titta i django/db/backends.
Använda en databasbackend från tredje part¶
Förutom de databaser som stöds officiellt finns det backends som tillhandahålls av tredje part som gör att du kan använda andra databaser med Django:
De Django-versioner och ORM-funktioner som stöds av dessa inofficiella backends varierar avsevärt. Frågor om de specifika funktionerna i dessa inofficiella backends, tillsammans med eventuella supportfrågor, bör riktas till de supportkanaler som tillhandahålls av varje tredjepartsprojekt.