Django
Migrations
Recherche…
Paramètres
django-admin | Détails |
---|---|
makemigrations <my_app> | Générer des migrations pour my_app |
makemigrations | Générer des migrations pour toutes les applications |
makemigrations --merge | Résoudre les conflits de migration pour toutes les applications |
makemigrations --merge <my_app> | Résoudre les conflits de migration pour my_app |
makemigrations --name <migration_name> <my_app> | Générer une migration pour my_app avec le nom migration_name |
migrate <my_app> | Appliquer les migrations en attente de my_app à la base de données |
migrate | Appliquer toutes les migrations en attente à la base de données |
migrate <my_app> <migration_name> | Appliquer ou non à la migration_name |
migrate <my_app> zero | Inapplicable toutes les migrations dans my_app |
sqlmigrate <my_app> <migration_name> | Imprime le SQL pour la migration nommée |
showmigrations | Affiche toutes les migrations pour toutes les applications |
showmigrations <my_app> | Affiche toutes les migrations dans my_app |
Travailler avec des migrations
Django utilise les migrations pour propager les modifications apportées à vos modèles dans votre base de données. La plupart du temps, Django peut les générer pour vous.
Pour créer une migration, exécutez:
$ django-admin makemigrations <app_name>
Cela créera un fichier de migration dans le sous-module de migration
app_name
. La première migration s'appellera 0001_initial.py
, l'autre commencera par 0002_
, puis 0003
, ...
Si vous omettez <app_name>
cela créera des migrations pour tous vos INSTALLED_APPS
.
Pour propager les migrations vers votre base de données, exécutez:
$ django-admin migrate <app_name>
Pour afficher toutes vos migrations, exécutez:
$ django-admin showmigrations app_name
app_name
[X] 0001_initial
[X] 0002_auto_20160115_1027
[X] 0003_somemodel
[ ] 0004_auto_20160323_1826
-
[X]
signifie que la migration a été propagée vers votre base de données -
[ ]
signifie que la migration n'a pas été propagée à votre base de données. Utilisezdjango-admin migrate
pour le propager
Vous appelez également les migrations de retour, cela peut être fait en transmettant le nom de la migration à la migrate command
. Compte tenu de la liste ci-dessus des migrations (montrée par 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
Migrations manuelles
Parfois, les migrations générées par Django ne sont pas suffisantes. Cela est particulièrement vrai lorsque vous souhaitez effectuer des migrations de données .
Par exemple, vous avez un tel modèle:
class Article(models.Model):
title = models.CharField(max_length=70)
Ce modèle possède déjà des données existantes et vous souhaitez maintenant ajouter un SlugField
:
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
Vous avez créé les migrations pour ajouter le champ, mais vous souhaitez maintenant définir le slug pour tous les articles existants, en fonction de leur title
.
Bien sûr, vous pourriez faire quelque chose comme ça dans le terminal:
$ 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()
...
>>>
Mais vous devrez le faire dans tous vos environnements (c.-à-d. Votre ordinateur de bureau, votre ordinateur portable, etc.), tous vos collègues devront le faire également, et vous devrez y réfléchir lors de la mise en scène et de la poussée. vivre.
Pour le faire une fois pour toutes, nous le ferons dans une migration. Commencez par créer une migration vide:
$ django-admin makemigrations --empty app_name
Cela créera un fichier de migration vide. Ouvrez-le, il contient un squelette de base. Disons que votre migration précédente s'appelait 0023_article_slug
et que celle-ci s'appelle 0024_auto_20160719_1734
. Voici ce que nous allons écrire dans notre fichier de migration:
# -*- 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.
]
Fausses migrations
Lorsqu'une migration est exécutée, Django stocke le nom de la migration dans une table django_migrations.
Créer et simuler des migrations initiales pour un schéma existant
Si votre application a déjà des modèles et des tables de base de données et ne dispose pas de migrations. Commencez par créer des migrations initiales pour votre application.
python manage.py makemigrations your_app_label
Faux migrations initiales maintenant appliquées
python manage.py migrate --fake-initial
Faux toutes les migrations dans toutes les applications
python manage.py migrate --fake
Fausses migrations d'applications uniques
python manage.py migrate --fake core
Faux fichier de migration unique
python manage.py migrate myapp migration_name
Noms personnalisés pour les fichiers de migration
Utilisez l' makemigrations --name <your_migration_name>
pour autoriser la dénomination des migrations au lieu d'utiliser un nom généré.
python manage.py makemigrations --name <your_migration_name> <app_name>
Résoudre les conflits de migration
introduction
Parfois, les migrations sont en conflit, ce qui rend la migration infructueuse. Cela peut se produire dans de nombreux scénarios, mais cela peut se produire régulièrement lors du développement d'une application avec une équipe.
Les conflits de migration courants se produisent lors de l'utilisation du contrôle de source, en particulier lorsque la méthode de fonctionnalité par branche est utilisée. Pour ce scénario, nous utiliserons un modèle appelé Reporter
avec le name
et l' address
attributs.
Deux développeurs à ce stade vont développer une fonctionnalité, ils obtiennent donc cette copie initiale du modèle Reporter
. Le développeur A ajoute un age
qui entraîne le fichier 0002_reporter_age.py
. Le développeur B ajoute un champ bank_account
qui 0002_reporter_bank_account
. Une fois que ces développeurs fusionnent leur code et tentent de migrer les migrations, un conflit de migration s'est produit.
Ce conflit se produit car ces migrations modifient le même modèle, Reporter
. De plus, les nouveaux fichiers commencent tous deux par 0002.
Fusion de migrations
Il y a plusieurs façons de le faire. Ce qui suit est dans l'ordre recommandé:
La solution la plus simple consiste à exécuter la commande makemigrations avec un indicateur --merge.
python manage.py makemigrations --merge <my_app>
Cela créera une nouvelle migration pour résoudre le conflit précédent.
Lorsque ce fichier supplémentaire n'est pas le bienvenu dans l'environnement de développement pour des raisons personnelles, vous pouvez supprimer les migrations en conflit. Ensuite, une nouvelle migration peut être effectuée à l'aide de la commande
makemigrations
. Lorsque des migrations personnalisées sont écrites, telles quemigrations.RunPython
, vous devez tenir compte de cette méthode.
Changer un CharField en un ForeignKey
Tout d'abord, supposons qu'il s'agisse de votre modèle initial, à l'intérieur d'une application appelée discography
:
from django.db import models
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Maintenant, vous vous rendez compte que vous voulez utiliser un ForeignKey pour l'artiste à la place. C'est un processus assez complexe, qui doit être fait en plusieurs étapes.
Étape 1, ajoutez un nouveau champ pour ForeignKey, en veillant à le marquer comme nul (notez que le modèle auquel nous sommes liés est également maintenant inclus):
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)
... et créer une migration pour ce changement.
./manage.py makemigrations discography
Étape 2, remplissez votre nouveau champ. Pour ce faire, vous devez créer une migration vide.
./manage.py makemigrations --empty --name transfer_artists discography
Une fois que vous avez cette migration vide, vous souhaitez y ajouter une seule opération RunPython
afin de lier vos enregistrements. Dans ce cas, cela pourrait ressembler à ceci:
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()
Maintenant que vos données sont transférées dans le nouveau champ, vous pouvez réellement le faire et tout laisser tel artist_link
, en utilisant le nouveau champ artist_link
pour tout. Ou, si vous souhaitez effectuer un peu de nettoyage, vous souhaitez créer deux autres migrations.
Pour votre première migration, vous souhaitez supprimer votre champ d'origine, artist
. Pour votre deuxième migration, renommez le nouveau champ artist_link
en artist
.
Cela se fait en plusieurs étapes pour s'assurer que Django reconnaît correctement les opérations.