Django
migraties
Zoeken…
parameters
django-admin commando | Details |
---|---|
makemigrations <my_app> | Genereer migraties voor my_app |
makemigrations | Genereer migraties voor alle apps |
makemigrations --merge | Los migratieconflicten op voor alle apps |
makemigrations --merge <my_app> | Migratieconflicten voor my_app |
makemigrations --name <migration_name> <my_app> | Genereer een migratie voor my_app met de naam migration_name |
migrate <my_app> | Pas lopende migraties van my_app op de database |
migrate | Pas alle uitstaande migraties toe op de database |
migrate <my_app> <migration_name> | Toepassen of niet meer toepassen op migration_name |
migrate <my_app> zero | Alle migraties in my_app |
sqlmigrate <my_app> <migration_name> | Hiermee wordt de SQL voor de genoemde migratie afgedrukt |
showmigrations | Toont alle migraties voor alle apps |
showmigrations <my_app> | Toont alle migraties in my_app |
Werken met migraties
Django gebruikt migraties om wijzigingen die u aanbrengt in uw modellen door te geven aan uw database. Meestal kan django ze voor u genereren.
Voer het volgende uit om een migratie te maken:
$ django-admin makemigrations <app_name>
Hiermee wordt een migratiebestand gemaakt in de migration
submodule van app_name
. De eerste migratie krijgt de naam 0001_initial.py
, de andere begint met 0002_
, daarna 0003
, ...
Als u <app_name>
dit migraties voor al uw INSTALLED_APPS
.
Voer de volgende stappen uit om migraties naar uw database door te geven:
$ django-admin migrate <app_name>
Voer het volgende uit om al uw migraties te tonen:
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[X] 0003_somemodel
[ ] 0004_auto_20160323_1826
-
[X]
betekent dat de migratie is doorgegeven aan uw database -
[ ]
betekent dat de migratie niet is doorgegeven aan uw database. Gebruikdjango-admin migrate
om het te verspreiden
U roept ook migraties terug, dit kunt u doen door de migratienaam door te geven aan de migrate command
. Gezien de bovenstaande lijst met migraties (getoond door 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
Handmatige migraties
Soms zijn migraties gegenereerd door Django niet voldoende. Dit geldt met name als u gegevensmigraties wilt maken.
Laten we bijvoorbeeld een dergelijk model hebben:
class Article(models.Model):
title = models.CharField(max_length=70)
Dit model heeft al bestaande gegevens en nu wilt u een SlugField
:
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
U hebt de migraties gemaakt om het veld toe te voegen, maar nu wilt u de slak instellen voor alle bestaande artikelen, op basis van hun title
.
Natuurlijk kun je zoiets in de terminal gewoon doen:
$ 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()
...
>>>
Maar je zult dit in al je omgevingen moeten doen (bijv. Je desktop op kantoor, je laptop, ...), al je collega's zullen dit ook moeten doen, en je moet erover nadenken bij het ensceneren en bij het pushen leven.
Om het voor eens en altijd te maken, doen we het in een migratie. Maak eerst een lege migratie:
$ django-admin makemigrations --empty app_name
Hiermee maakt u een leeg migratiebestand. Open het, het bevat een basisskelet. Stel dat uw vorige migratie de naam 0023_article_slug
en deze heeft de naam 0024_auto_20160719_1734
. Hier is wat we zullen schrijven in ons migratiebestand:
# -*- 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.
]
Valse migraties
Wanneer een migratie wordt uitgevoerd, slaat Django de naam van de migratie op in een tabel django_migrations.
Maak en valse initiële migraties voor een bestaand schema
Als uw app al modellen en databasetabellen heeft en geen migraties heeft. Maak eerst de initiële migraties voor uw app.
python manage.py makemigrations your_app_label
Nu nep initiële migraties zoals toegepast
python manage.py migrate --fake-initial
Nep alle migraties in alle apps
python manage.py migrate --fake
Valse single app-migraties
python manage.py migrate --fake core
Nep nep migratiebestand
python manage.py migrate myapp migration_name
Aangepaste namen voor migratiebestanden
Gebruik de optie makemigrations --name <your_migration_name>
om de migratie (s) een naam te geven in plaats van een gegenereerde naam te gebruiken.
python manage.py makemigrations --name <your_migration_name> <app_name>
Migratieconflicten oplossen
Invoering
Soms conflicteren migraties, waardoor de migratie mislukt. Dit kan in veel scenario's gebeuren, maar het kan regelmatig voorkomen bij het ontwikkelen van een app met een team.
Veelvoorkomende migratieconflicten treden op tijdens het gebruik van bronbeheer, vooral wanneer de methode feature-per-branch wordt gebruikt. Voor dit scenario gebruiken we een model met de name
Reporter
met de attributen name
en address
.
Twee ontwikkelaars gaan op dit moment een functie ontwikkelen, dus krijgen ze allebei dit eerste exemplaar van het Reporter
model. Ontwikkelaar A voegt een age
die resulteert in het bestand 0002_reporter_age.py
. Developer B voegt een bank_account
veld dat resulsts in 0002_reporter_bank_account
. Zodra deze ontwikkelaars hun code samenvoegen en proberen de migraties te migreren, trad een migratieconflict op.
Dit conflict treedt op omdat beide migraties hetzelfde model, Reporter
. Bovendien beginnen de nieuwe bestanden beide met 0002.
Migraties samenvoegen
Er zijn verschillende manieren om dit te doen. Het volgende is in de aanbevolen volgorde:
De meest eenvoudige oplossing hiervoor is door de opdracht makemigrations uit te voeren met een vlag --merge.
python manage.py makemigrations --merge <my_app>
Dit zal een nieuwe migratie creëren die het vorige conflict oplost.
Wanneer dit extra bestand om persoonlijke redenen niet welkom is in de ontwikkelomgeving, is een optie om de conflicterende migraties te verwijderen. Vervolgens kan een nieuwe migratie worden gemaakt met behulp van de reguliere opdracht
makemigrations
. Wanneer aangepaste migraties worden geschreven, zoalsmigrations.RunPython
.migrations.RunPython
, moet met deze methode worden verantwoord.
Verander een CharField in een ForeignKey
Laten we eerst aannemen dat dit uw eerste model is, binnen een applicatie genaamd discography
:
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Nu realiseer je je dat je in plaats daarvan een ForeignKey voor de artiest wilt gebruiken. Dit is een ietwat complex proces, dat in verschillende stappen moet worden uitgevoerd.
Stap 1, voeg een nieuw veld toe voor de ForeignKey en zorg ervoor dat het als nul wordt gemarkeerd (merk op dat het model waarnaar we linken nu ook is opgenomen):
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)
... en maak een migratie voor deze wijziging.
./manage.py makemigrations discography
Stap 2, vul uw nieuwe veld in. Om dit te doen, moet u een lege migratie maken.
./manage.py makemigrations --empty --name transfer_artists discography
Zodra u deze lege migratie heeft, wilt u er een enkele RunPython
bewerking aan toevoegen om uw records te koppelen. In dit geval kan het er ongeveer zo uitzien:
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 uw gegevens naar het nieuwe veld zijn overgebracht, kunt u eigenlijk alles doen en alles laten zoals het is, met het nieuwe veld artist_link
voor alles. Of, als u een beetje wilt opschonen, wilt u nog twee migraties maken.
Voor uw eerste migratie wilt u uw oorspronkelijke veld, artist
. artist_link
voor uw tweede migratie het nieuwe veld artist_link
naar artist
.
Dit gebeurt in meerdere stappen om ervoor te zorgen dat Django de bewerkingen correct herkent.