Django
Migracje
Szukaj…
Parametry
polecenie django-admin | Detale |
---|---|
makemigrations <my_app> | Generuj migracje dla my_app |
makemigrations | Generuj migracje dla wszystkich aplikacji |
makemigrations --merge | Rozwiąż konflikty migracyjne dla wszystkich aplikacji |
makemigrations --merge <my_app> | Rozwiąż konflikty migracyjne dla my_app |
makemigrations --name <migration_name> <my_app> | Generowanie migracji dla my_app pod nazwą migration_name |
migrate <my_app> | Zastosuj oczekujące migracje my_app do bazy danych |
migrate | Zastosuj wszystkie oczekujące migracje do bazy danych |
migrate <my_app> <migration_name> | Zastosuj lub usuń do migration_name |
migrate <my_app> zero | Anuluj wszystkie migracje w my_app |
sqlmigrate <my_app> <migration_name> | Wyświetla kod SQL dla nazwanej migracji |
showmigrations | Pokazuje wszystkie migracje dla wszystkich aplikacji |
showmigrations <my_app> | Pokazuje wszystkie migracje w my_app |
Praca z migracjami
Django używa migracji do propagowania zmian wprowadzanych w modelach do bazy danych. Przez większość czasu django może je dla Ciebie wygenerować.
Aby utworzyć migrację, uruchom:
$ django-admin makemigrations <app_name>
Spowoduje to utworzenie pliku migracji w migration
modułem z app_name
. Pierwsza migracja będzie nosić nazwę 0001_initial.py
, druga rozpocznie się od 0002_
, a następnie 0003
, ...
Pominięcie <app_name>
spowoduje utworzenie migracji dla wszystkich INSTALLED_APPS
.
Aby propagować migracje do bazy danych, uruchom:
$ django-admin migrate <app_name>
Aby wyświetlić wszystkie migracje, uruchom:
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[X] 0003_somemodel
[ ] 0004_auto_20160323_1826
-
[X]
oznacza, że migracja została propagowana do Twojej bazy danych -
[ ]
oznacza, że migracja nie została propagowana do Twojej bazy danych. Aby go propagować, użyj narzędziadjango-admin migrate
Wywołujesz także przywracanie migracji, można to zrobić, przekazując nazwę migracji do migrate command
. Biorąc pod uwagę powyższą listę migracji (pokazaną przez 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
Ręczne migracje
Czasami migracje generowane przez Django nie są wystarczające. Jest to szczególnie ważne, gdy chcesz przeprowadzić migrację danych .
Na przykład, niech masz taki model:
class Article(models.Model):
title = models.CharField(max_length=70)
Ten model ma już istniejące dane, a teraz chcesz dodać SlugField
:
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
Utworzyłeś migracje, aby dodać pole, ale teraz chcesz ustawić ślimak dla wszystkich istniejących artykułów, zgodnie z ich title
.
Oczywiście możesz po prostu zrobić coś takiego w terminalu:
$ 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()
...
>>>
Ale będziesz musiał to zrobić we wszystkich swoich środowiskach (tj. Na biurowym pulpicie, twoim laptopie, ...), wszyscy twoi współpracownicy również będą musieli to zrobić, i będziesz musiał pomyśleć o tym podczas wystawiania i pchania relacja na żywo.
Aby to zrobić raz na zawsze, zrobimy to podczas migracji. Najpierw utwórz pustą migrację:
$ django-admin makemigrations --empty app_name
Spowoduje to utworzenie pustego pliku migracji. Otwórz, zawiera podstawowy szkielet. Załóżmy, że Twoja poprzednia migracja nosiła nazwę 0023_article_slug
a ta nosi nazwę 0024_auto_20160719_1734
. Oto, co napiszemy w naszym pliku migracji:
# -*- 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.
]
Fałszywe migracje
Po uruchomieniu migracji Django przechowuje nazwę migracji w tabeli django_migrations.
Twórz i fałszuj początkowe migracje dla istniejącego schematu
Jeśli Twoja aplikacja ma już modele i tabele bazy danych i nie ma migracji. Najpierw utwórz początkowe migracje dla swojej aplikacji.
python manage.py makemigrations your_app_label
Teraz zastosuj fałszywe migracje początkowe
python manage.py migrate --fake-initial
Fałszywe wszystkie migracje we wszystkich aplikacjach
python manage.py migrate --fake
Fałszywe migracje pojedynczych aplikacji
python manage.py migrate --fake core
Fałszywy pojedynczy plik migracji
python manage.py migrate myapp migration_name
Niestandardowe nazwy plików migracji
Użyj opcji makemigrations --name <your_migration_name>
, aby zezwolić na nazwanie migracji zamiast używania wygenerowanej nazwy.
python manage.py makemigrations --name <your_migration_name> <app_name>
Rozwiązywanie konfliktów migracyjnych
Wprowadzenie
Czasami migracje powodują konflikty, co powoduje, że migracja kończy się niepowodzeniem. Może się to zdarzyć w wielu sceneriach, jednak może się zdarzyć regularnie podczas opracowywania jednej aplikacji z zespołem.
Typowe konflikty migracyjne zdarzają się podczas korzystania z kontroli źródła, szczególnie gdy używana jest metoda funkcja dla gałęzi. W tym scenariuszu użyjemy modelu o nazwie Reporter
z name
i address
atrybutu.
Dwóch programistów w tym momencie zamierza opracować funkcję, dlatego oboje otrzymują tę początkową kopię modelu Reporter
. Deweloper A dodaje age
co powoduje utworzenie pliku 0002_reporter_age.py
. Deweloper B dodaje pole bank_account
które 0002_reporter_bank_account
w 0002_reporter_bank_account
. Gdy ci programiści scalą razem swój kod i spróbują przeprowadzić migrację, wystąpił konflikt migracyjny.
Ten konflikt występuje, ponieważ obie migracje zmieniają ten sam model Reporter
. Ponadto oba nowe pliki zaczynają się od 0002.
Scalanie migracji
Można to zrobić na kilka sposobów. Poniższa kolejność jest zalecana:
Najprostszym rozwiązaniem tego problemu jest uruchomienie polecenia makemigrations z flagą --merge.
python manage.py makemigrations --merge <my_app>
Spowoduje to utworzenie nowej migracji rozwiązującej poprzedni konflikt.
Jeśli ten dodatkowy plik nie jest mile widziany w środowisku programistycznym z powodów osobistych, można usunąć migracje powodujące konflikt. Następnie można przeprowadzić nową migrację za pomocą zwykłego polecenia
makemigrations
. Podczas pisania niestandardowych migracji, takich jakmigrations.RunPython
, należy uwzględnić tę metodę.
Zmień CharField na ForeignKey
Po pierwsze, załóżmy, że to twój początkowy model w aplikacji o nazwie discography
:
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Teraz zdajesz sobie sprawę, że zamiast tego chcesz użyć klucza zagranicznego dla artysty. Jest to dość złożony proces, który należy wykonać w kilku etapach.
Krok 1, dodaj nowe pole dla klucza ForeignKey, upewniając się, że oznaczono je jako null (zwróć uwagę, że model, z którym się łączymy, jest teraz dołączony):
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)
... i utwórz migrację dla tej zmiany.
./manage.py makemigrations discography
Krok 2, wypełnij nowe pole. Aby to zrobić, musisz utworzyć pustą migrację.
./manage.py makemigrations --empty --name transfer_artists discography
Po zakończeniu tej pustej migracji chcesz dodać do niej pojedynczą operację RunPython
, aby połączyć swoje rekordy. W takim przypadku może wyglądać mniej więcej tak:
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()
Teraz, gdy Twoje dane są przenoszone do nowego pola, możesz faktycznie zrobić i pozostawić wszystko bez artist_link
, używając nowego pola artist_link
do wszystkiego. Lub, jeśli chcesz zrobić trochę czyszczenia, chcesz utworzyć dwie kolejne migracje.
Podczas pierwszej migracji będziesz chciał usunąć swoje oryginalne pole, artist
. Podczas drugiej migracji zmień nazwę nowego pola artist_link
na artist
.
Odbywa się to w kilku krokach, aby zapewnić prawidłowe rozpoznanie operacji przez Django.