Migrationsverksamhet¶
Migreringsfiler består av en eller flera ”Operation”-objekt, objekt som deklarativt registrerar vad migreringen ska göra med din databas.
Django använder också dessa Operation
-objekt för att räkna ut hur dina modeller såg ut historiskt och för att beräkna vilka ändringar du har gjort i dina modeller sedan den senaste migreringen så att den automatiskt kan skriva dina migreringar; det är därför de är deklarativa, eftersom det betyder att Django enkelt kan ladda dem alla i minnet och köra igenom dem utan att röra databasen för att räkna ut hur ditt projekt ska se ut.
Det finns också mer specialiserade Operation
-objekt som är till för saker som :ref:datamigreringar <data-migrations>
och för avancerad manuell databasmanipulation. Du kan också skriva dina egna Operation
-klasser om du vill kapsla in en anpassad förändring som du ofta gör.
Om du behöver en tom migreringsfil för att skriva in dina egna Operation
-objekt i, använd python manage.py makemigrations --empty yourappname
, men tänk på att manuellt tillägg av schemaändrande operationer kan förvirra migreringsautodetektorn och göra att resulterande körningar av makemigrations
ger felaktig kod.
Alla Django-kärnoperationer är tillgängliga från modulen django.db.migrations.operations
.
För introduktionsmaterial, se migrations topic guide.
Schema-verksamhet¶
SkapaModell
¶
Skapar en ny modell i projekthistoriken och en motsvarande tabell i databasen för att matcha den.
name
är modellnamnet, som det skulle skrivas i filen models.py
.
fields
är en lista med 2-tuples av (field_name, field_instance)
. Fältinstansen ska vara ett obundet fält (så bara models.CharField(...)
, snarare än ett fält som hämtats från en annan modell).
options
är en valfri ordlista med värden från modellens Meta
-klass.
bases
är en valfri lista över andra klasser som den här modellen ska ärva från; den kan innehålla både klassobjekt och strängar i formatet "appname.ModelName"
om du vill vara beroende av en annan modell (så att du ärver från den historiska versionen). Om den inte anges ärver den som standard från standardmodellen models.Model
.
managers
tar en lista med 2-tuples av (manager_name, manager_instance)
. Den första hanteraren i listan kommer att vara standardhanteraren för den här modellen under migreringar.
DeleteModel
¶
Raderar modellen från projekthistoriken och dess tabell från databasen.
RenameModel
¶
Byter namn på modellen från ett gammalt namn till ett nytt.
Du kan behöva lägga till detta manuellt om du ändrar modellens namn och en hel del av dess fält på en gång. För autodetektorn ser det ut som om du har tagit bort en modell med det gamla namnet och lagt till en ny med ett annat namn, och den migrering som skapas kommer att förlora alla data i den gamla tabellen.
AlterModelTable
¶
Ändrar modellens tabellnamn (alternativet db_table
på underklassen Meta
).
AlterModelTableKommentar
¶
Ändrar modellens tabellkommentar (alternativet db_table_comment
på underklassen Meta
).
AlterUniqueTogether
¶
Ändrar modellens uppsättning av unika begränsningar (alternativet unique_together
på underklassen Meta
).
AlterIndexTillsamman
¶
Ändrar modellens uppsättning av anpassade index (alternativet index_together
i underklassen Meta
).
Varning
AlterIndexTogether
stöds officiellt endast för migreringsfiler från före Django 4.2. Av bakåtkompatibilitetsskäl är det fortfarande en del av det offentliga API:et, och det finns ingen plan att avskriva eller ta bort det, men det bör inte användas för nya migreringar. Använd istället AddIndex
och RemoveIndex
.
AlterOrderMedAvseendePå
¶
Skapar eller tar bort kolumnen _order
som behövs för alternativet order_with_respect_to
på subklassen Meta
.
AlterModelOptions
¶
Lagrar ändringar av olika modellalternativ (inställningar på en modells Meta
) som permissions
och verbose_name
. Påverkar inte databasen, men lagrar dessa ändringar så att RunPython
-instanser kan använda dem. options
bör vara en ordbok som mappar alternativnamn till värden.
AlterModelManagers
¶
Ändrar de chefer som är tillgängliga under migreringar.
AddField
¶
Lägger till ett fält till en modell. model_name
är modellens namn, name
är fältets namn och field
är en obunden fältinstans (det som du skulle lägga till i fältdeklarationen i models.py
- till exempel models.IntegerField(null=True)
.
Argumentet preserve_default
anger om fältets standardvärde är permanent och ska bakas in i projekttillståndet (True
), eller om det är tillfälligt och bara för den här migreringen (False
) - vanligtvis för att migreringen lägger till ett icke-nullbart fält i en tabell och behöver ett standardvärde att lägga in i befintliga rader. Det påverkar inte beteendet att ställa in standardvärden i databasen direkt - Django ställer aldrig in standardvärden i databasen och tillämpar dem alltid i Django ORM-koden.
Varning
I äldre databaser kan tillägg av ett fält med ett standardvärde leda till att tabellen skrivs om helt och hållet. Detta händer även för nollställbara fält och kan ha en negativ inverkan på prestandan. För att undvika detta bör följande steg vidtas.
Lägg till det nollställbara fältet utan standardvärde och kör kommandot
makemigrations
. Detta bör generera en migrering med enAddField
-åtgärd.Lägg till standardvärdet i ditt fält och kör kommandot
makemigrations
. Detta bör generera en migrering med enAlterField
-åtgärd.
Avlägsna fält
¶
Tar bort ett fält från en modell.
Tänk på att detta faktiskt innebär att ett fält läggs till i en modell när det vänds. Åtgärden är reversibel (bortsett från eventuell dataförlust, som är irreversibel) om fältet är nollställbart eller om det har ett standardvärde som kan användas för att fylla i den återskapade kolumnen. Om fältet inte är nollställbart och inte har något standardvärde är åtgärden irreversibel.
PostgreSQL
RemoveField
kommer också att radera alla ytterligare databasobjekt som är relaterade till det borttagna fältet (som till exempel vyer). Detta beror på att den resulterande DROP COLUMN
-satsen kommer att innehålla CASCADE
-klausulen för att säkerställa att beroende objekt utanför tabellen också tas bort.
AlterField
¶
Ändrar ett fälts definition, inklusive ändringar av dess typ, null
, unique
, db_column
och andra fältattribut.
Argumentet preserve_default
anger om fältets standardvärde är permanent och ska bakas in i projekttillståndet (True
), eller om det är tillfälligt och bara för den här migreringen (False
) - vanligtvis för att migreringen ändrar ett nollställbart fält till ett icke-nullställbart och behöver ett standardvärde att lägga in i befintliga rader. Det påverkar inte beteendet att ställa in standardvärden i databasen direkt - Django ställer aldrig in standardvärden i databasen och tillämpar dem alltid i Django ORM-koden.
Observera att alla ändringar inte är möjliga i alla databaser - du kan t.ex. inte ändra ett fält av texttyp som models.TextField()
till ett fält av siffertyp som models.IntegerField()
i de flesta databaser.
RenameField
¶
Ändrar ett fälts namn (och, om inte db_column
har angetts, dess kolumnnamn).
AddIndex
¶
Skapar ett index i databastabellen för modellen med model_name
. index
är en instans av klassen Index
.
RemoveIndex
¶
Tar bort indexet med namnet name
från modellen med model_name
.
RenameIndex
¶
Byter namn på ett index i databastabellen för modellen med model_name
. Exakt ett av old_name
och old_fields
kan anges. old_fields
är en iterabel av strängarna, som ofta motsvarar fält i index_together
(alternativ före Django 5.1).
I databaser som inte stöder en indexomdöpning (SQLite och MariaDB < 10.5.2) kommer åtgärden att ta bort och återskapa indexet, vilket kan bli dyrt.
AddConstraint
¶
Skapar en constraint i databastabellen för modellen med model_name
.
”Ta bort begränsning¶
Tar bort begränsningen med namnet namn
från modellen med modell_namn
.
AlterConstraint
¶
Ändrar begränsningen med namnet name
i modellen med model_name
med den nya constraint
utan att påverka databasen.
Specialoperationer¶
RunSQL
¶
Gör det möjligt att köra godtycklig SQL på databasen - användbart för mer avancerade funktioner i databasbackends som Django inte stöder direkt.
sql
, och reverse_sql
om det tillhandahålls, bör vara strängar av SQL som ska köras på databasen. På de flesta databasbackends (alla utom PostgreSQL) kommer Django att dela upp SQL i enskilda uttalanden innan de körs.
Varning
På PostgreSQL och SQLite, använd endast BEGIN
eller COMMIT
i din SQL i non-atomic migrations, för att undvika att bryta Djangos transaktionsstatus.
Du kan också skicka en lista med strängar eller 2-tupler. Den senare används för att skicka frågor och parametrar på samma sätt som cursor.execute(). Dessa tre operationer är likvärdiga:
migrations.RunSQL("INSERT INTO musician (name) VALUES ('Reinhardt');")
migrations.RunSQL([("INSERT INTO musician (name) VALUES ('Reinhardt');", None)])
migrations.RunSQL([("INSERT INTO musician (name) VALUES (%s);", ["Reinhardt"])])
Om du vill inkludera bokstavliga procenttecken i frågan måste du dubbla dem om du skickar parametrar.
Frågorna reverse_sql
körs när migreringen inte tillämpas. De bör ångra det som gjorts av `sql
-frågorna. Till exempel:, för att ångra ovanstående infogning med en borttagning:
migrations.RunSQL(
sql=[("INSERT INTO musician (name) VALUES (%s);", ["Reinhardt"])],
reverse_sql=[("DELETE FROM musician where name=%s;", ["Reinhardt"])],
)
Om reverse_sql
är None
(standard) är RunSQL
-operationen irreversibel.
Med argumentet state_operations
kan du ange operationer som är likvärdiga med SQL när det gäller projektstatus. Om du till exempel skapar en kolumn manuellt bör du skicka in en lista som innehåller en AddField
operation här så att autodetektorn fortfarande har ett uppdaterat tillstånd för modellen. Om du inte gör det, när du nästa gång kör makemigrations
, kommer den inte att se någon operation som lägger till det fältet och kommer därför att försöka köra den igen. Till exempel:
migrations.RunSQL(
"ALTER TABLE musician ADD COLUMN name varchar(255) NOT NULL;",
state_operations=[
migrations.AddField(
"musician",
"name",
models.CharField(max_length=255),
),
],
)
Det valfria argumentet hints
kommer att skickas som **hints
till metoden allow_migrate`()
i databasroutrar för att hjälpa dem att fatta beslut om routning. Se Tips för mer information om databastips.
Det valfria argumentet elidable
avgör om åtgärden ska tas bort (elided) när :ref:``squashing migrations <migration-squashing>`.
- RunSQL.noop¶
Skicka attributet
RunSQL.noop
tillsql
ellerreverse_sql
när du vill att operationen inte ska göra någonting i den angivna riktningen. Detta är särskilt användbart för att göra operationen reversibel.
RunPython
¶
Kör anpassad Python-kod i ett historiskt sammanhang. code
(och reverse_code
om det tillhandahålls) ska vara anropsbara objekt som accepterar två argument; det första är en instans av django.apps.registry.Apps
som innehåller historiska modeller som matchar operationens plats i projekthistoriken, och det andra är en instans av SchemaEditor
.
Argumentet reverse_code
anropas vid avapplicering av migreringar. Denna anropbara bör ångra vad som gjorts i den anropbara code
så att migreringen är reversibel. Om reverse_code
är None
(standard), är RunPython
-operationen irreversibel.
Det valfria argumentet hints
kommer att skickas som **hints
till metoden allow_migrate`()
i databasroutrar för att hjälpa dem att fatta ett routningsbeslut. Se Tips för mer information om databastips.
Det valfria argumentet elidable
avgör om åtgärden ska tas bort (elided) när :ref:``squashing migrations <migration-squashing>`.
Vi rekommenderar att du skriver koden som en separat funktion ovanför klassen Migration
i migreringsfilen och skickar den till RunPython
. Här är ett exempel på hur du använder RunPython
för att skapa några initiala objekt på en Country
-modell:
from django.db import migrations
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).bulk_create(
[
Country(name="USA", code="us"),
Country(name="France", code="fr"),
]
)
def reverse_func(apps, schema_editor):
# forwards_func() creates two Country instances,
# so reverse_func() should delete them.
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).filter(name="USA", code="us").delete()
Country.objects.using(db_alias).filter(name="France", code="fr").delete()
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(forwards_func, reverse_func),
]
Detta är i allmänhet den operation du skulle använda för att skapa :ref:datamigreringar <data-migrations>
, köra anpassade datauppdateringar och ändringar och allt annat du behöver tillgång till en ORM och/eller Python-kod för.
Precis som RunSQL
, se till att om du ändrar schema här inne gör du det antingen utanför omfattningen av Djangos modellsystem (t.ex. triggers) eller att du använder SeparateDatabaseAndState
för att lägga till operationer som återspeglar dina ändringar i modelltillståndet - annars kommer den versionerade ORM och autodetektorn att sluta fungera korrekt.
Som standard kommer RunPython
att köra sitt innehåll inuti en transaktion på databaser som inte stöder DDL-transaktioner (till exempel MySQL och Oracle). Detta bör vara säkert, men kan orsaka en krasch om du försöker använda schema_editor
som tillhandahålls på dessa backends; i detta fall, skicka atomic=False
till RunPython
-operationen.
På databaser som stöder DDL-transaktioner (SQLite och PostgreSQL) har RunPython
-operationer inga transaktioner som automatiskt läggs till förutom de transaktioner som skapas för varje migrering. Således, till exempel på PostgreSQL, bör du undvika att kombinera schemaändringar och RunPython
-operationer i samma migrering, annars kan du träffa fel som OperationalError: cannot ALTER TABLE "mytable" because it has pending trigger events
.
Om du har en annan databas och inte är säker på om den stöder DDL-transaktioner, kontrollera attributet django.db.connection.features.can_rollback_ddl
.
Om åtgärden RunPython
är en del av en non-atomic migration, kommer åtgärden endast att utföras i en transaktion om atomic=True
skickas till åtgärden RunPython
.
Varning
RunPython
ändrar inte magiskt anslutningen av modellerna åt dig; alla modellmetoder du anropar kommer att gå till standarddatabasen om du inte ger dem det aktuella databasaliaset (tillgängligt från schema_editor.connection.alias
, där schema_editor
är det andra argumentet till din funktion).
SepareraDatabasOchStatus
¶
En mycket specialiserad operation som gör det möjligt att kombinera databasaspekter (schemaändring) och statliga aspekter (autodetektorkraft) av operationer.
Den accepterar två listor med operationer. När du blir ombedd att tillämpa tillstånd kommer den att använda listan `` state_operations`` (detta är en generaliserad version av RunSQL
’s `` state_operations`` argument). När den ombeds att tillämpa ändringar i databasen kommer den att använda listan database_operations
.
Om databasens faktiska tillstånd och Djangos syn på tillståndet inte är synkroniserade kan detta bryta migreringsramverket och till och med leda till dataförlust. Det är värt att vara försiktig och kontrollera dina databas- och tillståndsoperationer noggrant. Du kan använda sqlmigrate
och dbshell
för att kontrollera dina databasoperationer. Du kan använda makemigrations
, särskilt med --dry-run
, för att kontrollera dina tillståndsoperationer.
För ett exempel på användning av SeparateDatabaseAndState
, se Ändra en ManyToManyField så att den använder en through-modell.
Operationskategori¶
Skriva din egen¶
Operationer har ett relativt enkelt API, och de är utformade så att du enkelt kan skriva dina egna för att komplettera de inbyggda Django. Den grundläggande strukturen för en Operation
ser ut så här:
from django.db.migrations.operations.base import Operation
class MyCustomOperation(Operation):
# If this is False, it means that this operation will be ignored by
# sqlmigrate; if true, it will be run and the SQL collected for its output.
reduces_to_sql = False
# If this is False, Django will refuse to reverse past this operation.
reversible = False
# This categorizes the operation. The corresponding symbol will be
# displayed by the makemigrations command.
category = OperationCategory.ADDITION
def __init__(self, arg1, arg2):
# Operations are usually instantiated with arguments in migration
# files. Store the values of them on self for later use.
pass
def state_forwards(self, app_label, state):
# The Operation should take the 'state' parameter (an instance of
# django.db.migrations.state.ProjectState) and mutate it to match
# any schema changes that have occurred.
pass
def database_forwards(self, app_label, schema_editor, from_state, to_state):
# The Operation should use schema_editor to apply any changes it
# wants to make to the database.
pass
def database_backwards(self, app_label, schema_editor, from_state, to_state):
# If reversible is True, this is called when the operation is reversed.
pass
def describe(self):
# This is used to describe what the operation does.
return "Custom Operation"
@property
def migration_name_fragment(self):
# Optional. A filename part suitable for automatically naming a
# migration containing this operation, or None if not applicable.
return "custom_operation_%s_%s" % (self.arg1, self.arg2)
Du kan ta den här mallen och arbeta utifrån den, men vi föreslår att du tittar på de inbyggda Django-operationerna i django.db.migrations.operations
- de täcker mycket av exempelanvändningen av semi-interna aspekter av migreringsramen som ProjectState
och de mönster som används för att få historiska modeller, liksom ModelState
och de mönster som används för att mutera historiska modeller i state_forwards()
.
Några saker att notera:
Du behöver inte lära dig så mycket om
ProjectState
för att skriva migreringar; du behöver bara veta att den har enapps
-egenskap som ger tillgång till ett appregister (som du sedan kan anropaget_model
på).database_forwards
ochdatabase_backwards
får båda två tillstånd skickade till sig; dessa representerar skillnaden somstate_forwards
-metoden skulle ha tillämpat, men ges till dig av bekvämlighets- och hastighetsskäl.Om du vill arbeta med modellklasser eller modellinstanser från argumentet
from_state
idatabase_forwards()
ellerdatabase_backwards()
måste du rendera modelltillstånd med metodenclear_delayed_apps_cache()
för att göra relaterade modeller tillgängliga:def database_forwards(self, app_label, schema_editor, from_state, to_state): # This operation should have access to all models. Ensure that all models are # reloaded in case any are delayed. from_state.clear_delayed_apps_cache() ...
to_state
i metoden database_backwards är det äldre tillståndet, det vill säga det som kommer att vara det aktuella tillståndet när migreringen har avslutats.Du kan se implementeringar av
references_model
på de inbyggda operationerna; detta är en del av autodetekteringskoden och spelar ingen roll för anpassade operationer.
Varning
Av prestandaskäl återanvänds Field
-instanser i ModelState.fields
över migreringar. Du får aldrig ändra attributen på dessa instanser. Om du behöver mutera ett fält i state_forwards()
måste du ta bort den gamla instansen från ModelState.fields
och lägga till en ny instans i dess ställe. Detsamma gäller för Manager
-instanser i ModelState.managers
.
Låt oss som ett exempel göra en operation som laddar PostgreSQL-tillägg (som innehåller några av PostgreSQL: s mer spännande funktioner). Eftersom det inte finns några förändringar i modelltillståndet är allt det gör att köra ett kommando:
from django.db.migrations.operations.base import Operation
class LoadExtension(Operation):
reversible = True
def __init__(self, name):
self.name = name
def state_forwards(self, app_label, state):
pass
def database_forwards(self, app_label, schema_editor, from_state, to_state):
schema_editor.execute("CREATE EXTENSION IF NOT EXISTS %s" % self.name)
def database_backwards(self, app_label, schema_editor, from_state, to_state):
schema_editor.execute("DROP EXTENSION %s" % self.name)
def describe(self):
return "Creates extension %s" % self.name
@property
def migration_name_fragment(self):
return "create_extension_%s" % self.name