Django
migreringar
Sök…
parametrar
django-admin kommando | detaljer |
---|---|
makemigrations <my_app> | Generera migreringar för my_app |
makemigrations | Generera migreringar för alla appar |
makemigrations --merge | Lös migrationskonflikter för alla appar |
makemigrations --merge <my_app> | Lös migrationskonflikter för my_app |
makemigrations --name <migration_name> <my_app> | Generera en migrering för my_app med namnet migration_name |
migrate <my_app> | Tillämpa väntande migreringar av my_app i databasen |
migrate | Använd alla väntande migrationer i databasen |
migrate <my_app> <migration_name> | Använd eller avaktivera upp till migration_name |
migrate <my_app> zero | Avlägsna alla migreringar i my_app |
sqlmigrate <my_app> <migration_name> | Skriver ut SQL för den namngivna migreringen |
showmigrations | Visar alla migreringar för alla appar |
showmigrations <my_app> | Visar alla migreringar i my_app |
Arbeta med migrationer
Django använder migreringar för att sprida ändringar du gör i dina modeller till din databas. Django kan oftast generera dem åt dig.
För att skapa en migrering, kör:
$ django-admin makemigrations <app_name>
Detta skapar en migreringsfil i migration
för app_name
. Den första migrationen kommer att kallas 0001_initial.py
, den andra kommer att börja med 0002_
, sedan 0003
, ...
Om du utelämnar <app_name>
skapar det migreringar för alla dina INSTALLED_APPS
.
För att sprida migreringar till din databas, kör:
$ django-admin migrate <app_name>
För att visa alla dina migrationer, kör:
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[X] 0003_somemodel
[ ] 0004_auto_20160323_1826
-
[X]
betyder att migreringen spridits till din databas -
[ ]
betyder att migreringen inte spridits till din databas. Använddjango-admin migrate
att sprida den
Du ringer också omvandla migrationer, detta kan göras genom att överföra migreringsnamnet till migrate command
. Med tanke på ovanstående lista över migrationer (visas av django-admin showmigrations
):
$ django-admin migrate app_name 0002 # Roll back to migration 0002
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[ ] 0003_somemodel
[ ] 0004_auto_20160323_1826
Manuella migreringar
Ibland är migrationer som genereras av Django inte tillräckliga. Detta gäller särskilt när du vill göra datamigreringar .
Låt oss till exempel ha en sådan modell:
class Article(models.Model):
title = models.CharField(max_length=70)
Den här modellen har redan befintliga data och nu vill du lägga till ett SlugField
:
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
Du skapade migreringarna för att lägga till fältet, men nu vill du ställa in snigeln för alla befintliga artiklar, enligt deras title
.
Naturligtvis kan du bara göra något liknande i terminalen:
$ django-admin shell
>>> from my_app.models import Article
>>> from django.utils.text import slugify
>>> for article in Article.objects.all():
... article.slug = slugify(article.title)
... article.save()
...
>>>
Men du måste göra detta i alla dina miljöer (dvs. ditt skrivbord, din bärbara dator, ...), alla dina medarbetare måste göra det också, och du kommer att behöva tänka på det på scenen och när du trycker leva.
För att göra det en gång för alla, kommer vi att göra det i en migration. Skapa först en tom migrering:
$ django-admin makemigrations --empty app_name
Detta skapar en tom migreringsfil. Öppna den, den innehåller ett basskelett. Låt oss säga att din tidigare migrering hette 0023_article_slug
och den här heter 0024_auto_20160719_1734
. Så här skriver vi i vår migreringsfil:
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-19 15:34
from __future__ import unicode_literals
from django.db import migrations
from django.utils.text import slugify
def gen_slug(apps, schema_editor):
# We can't import the Article model directly as it may be a newer
# version than this migration expects. We use the historical version.
Article = apps.get_model('app_name', 'Article')
for row in Article.objects.all():
row.slug = slugify(row.name)
row.save()
class Migration(migrations.Migration):
dependencies = [
('hosting', '0023_article_slug'),
]
operations = [
migrations.RunPython(gen_slug, reverse_code=migrations.RunPython.noop),
# We set `reverse_code` to `noop` because we cannot revert the migration
# to get it back in the previous state.
# If `reverse_code` is not given, the migration will not be reversible,
# which is not the behaviour we expect here.
]
Falska migrationer
När en migrering körs lagrar Django namnet på migreringen i en django_migrations-tabell.
Skapa och förfalska initiala migreringar för befintligt schema
Om din app redan har modeller och databastabeller och inte har migreringar. Skapa först initiala migreringar för din app.
python manage.py makemigrations your_app_label
Nu falska initiala migrationer som tillämpats
python manage.py migrate --fake-initial
Fake all migration i alla appar
python manage.py migrate --fake
Fake enstaka app migrationer
python manage.py migrate --fake core
Fake enda migreringsfil
python manage.py migrate myapp migration_name
Anpassade namn för migreringsfiler
Använd makemigrations --name <your_migration_name>
att tillåta namnge migreringarna i stället för att använda ett genererat namn.
python manage.py makemigrations --name <your_migration_name> <app_name>
Lösa migrationskonflikter
Introduktion
Ibland konflikter migrationer, vilket resulterar i att migrationen är osuccesfull. Detta kan hända i många scenerier, men det kan uppstå regelbundet när man utvecklar en app med ett team.
Vanliga migrationskonflikter inträffar när man använder källkontroll, särskilt när metoden per filial används. För det här scenariot kommer vi att använda en modell som heter Reporter
med attributens name
och address
.
Två utvecklare vid denna tidpunkt kommer att utveckla en funktion, varför de båda får den här första kopian av Reporter
modellen. Utvecklare A lägger till en age
som resulterar i filen 0002_reporter_age.py
filen. Developer B ger en bank_account
fält som resulsts i 0002_reporter_bank_account
. När dessa utvecklare smälter samman sin kod och försökte migrera migreringarna inträffade en migrationskonflikt.
Denna konflikt inträffar eftersom dessa migrationer båda förändrar samma modell, Reporter
. Dessutom börjar de nya filerna båda med 0002.
Slå samman migreringar
Det finns flera sätt att göra det på. Följande är i den rekommenderade ordningen:
Den enklaste fixen för detta är genom att köra kommandot makemigrations med en - flagg.
python manage.py makemigrations --merge <my_app>
Detta skapar en ny migrering som löser den tidigare konflikten.
När denna extra fil av personliga skäl inte är välkommen i utvecklingsmiljön, är ett alternativ att ta bort de motstridiga migrationerna. Sedan kan en ny migrering göras med kommandot vanliga
makemigrations
. När anpassade migrationer skrivs, till exempelmigrations.RunPython
, måste redovisas för att använda den här metoden.
Byt ett CharField till ett ForeignKey
Först och främst, låt oss anta att detta är din ursprungliga modell, i en applikation som kallas discography
:
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Nu inser du att du istället vill använda ett ForeignKey för artisten. Detta är en något komplex process som måste göras i flera steg.
Steg 1, lägg till ett nytt fält för ForeignKey och se till att markera det som null (Observera att modellen vi länkar till också nu ingår):
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
artist_link = models.ForeignKey('Artist', null=True)
class Artist(models.Model):
name = models.CharField(max_length=255)
... och skapa en migrering för den här förändringen.
./manage.py makemigrations discography
Steg 2, fyll i ditt nya fält. För att göra detta måste du skapa en tom migrering.
./manage.py makemigrations --empty --name transfer_artists discography
När du har tagit den tomma migreringen vill du lägga till en enda RunPython
operation till den för att länka dina poster. I det här fallet kan det se ut så här:
def link_artists(apps, schema_editor):
Album = apps.get_model('discography', 'Album')
Artist = apps.get_model('discography', 'Artist')
for album in Album.objects.all():
artist, created = Artist.objects.get_or_create(name=album.artist)
album.artist_link = artist
album.save()
Nu när dina data överförs till det nya fältet kan du faktiskt göra det och lämna allt som det är, med det nya artist_link
fältet för allt. Eller, om du vill göra en del sanering, vill du skapa ytterligare två migrationer.
För din första migrering vill du ta bort ditt ursprungliga fält, artist
. För din andra migrering, byta namn på det nya fältet artist_link
till artist
.
Detta görs i flera steg för att säkerställa att Django känner igen operationerna korrekt.