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.