Migrations¶
Les migrations sont la maniĂšre par laquelle Django propage des modifications que vous apportez Ă des modĂšles (ajout dâun champ, suppression dâun modĂšle, etc.) dans un schĂ©ma de base de donnĂ©es. Elles sont conçues pour ĂȘtre quasiment automatiques, mais vous aurez besoin de savoir quand crĂ©er les migrations, quand les exĂ©cuter, et les problĂšmes courants que vous pourriez rencontrer.
Un historique rapide¶
Avant la version 1.7, Django ne savait que gĂ©rer lâajout de nouveaux modĂšles Ă la base de donnĂ©es ; il nâĂ©tait pas possible de modifier ou supprimer des modĂšles existants via la commande syncdb (le prĂ©dĂ©cesseur de migrate).
Des outils externes, notamment South, permettaient ces autres types de modifications, mais la fonctionnalitĂ© a Ă©tĂ© jugĂ© suffisamment importante pour quâelle soit intĂ©grĂ©e au noyau Django.
Les commandes¶
Il y a plusieurs commandes utiles pour interagir avec les migrations et manipuler le schéma de base de données avec Django :
- migrate, qui est responsable de lâexĂ©cution des migrations, de leur annulation ainsi que de la gestion de leur Ă©tat. 
- makemigrations, qui est responsable de la création de nouvelles migrations en fonction des modifications que vous avez apportées aux modÚles. 
- sqlmigrate, qui affiche les instructions SQL correspondant Ă une migration. 
Il est intĂ©ressant de noter que les migrations sont créées et gĂ©rĂ©es par application. En particulier, il est possible dâavoir des applications qui nâutilisent pas les migrations (celles-ci sont considĂ©rĂ©es comme des applications « non migrĂ©es ») ; ces applications utiliseront le comportement prĂ©cĂ©dent de Django, qui consiste simplement Ă ajouter les nouveaux modĂšles.
Vous devez imaginer les migrations comme un systĂšme de contrĂŽle de versions pour un schĂ©ma de base de donnĂ©es. makemigrations se charge de regrouper vos changements de modĂšle dans des fichiers de migration individuels - comme des commits - et migrate est chargĂ© dâappliquer les changements Ă la base de donnĂ©es.
Les fichiers de migration pour chaque application sont stockĂ©s dans un rĂ©pertoire « migrations » Ă lâintĂ©rieur de lâapplication, et sont conçus pour faire partie du code source et de la distribution de cette application. Les migrations sont créées une fois sur votre machine de dĂ©veloppement, puis exĂ©cutĂ©es telles quelles sur les machines de vos collĂšgues, les machines de tests, et finalement sur les machines de production.
Note
Pour chaque application, il est possible de redéfinir le nom du paquet qui contient les migrations en utilisant le réglage MIGRATION_MODULES.
Les migrations se dĂ©roulent toujours de la mĂȘme maniĂšre lorsquâelles sont appliquĂ©es sur un mĂȘme ensemble de donnĂ©es et leurs rĂ©sultats sont constants et rĂ©pĂ©tables, ce qui signifie que ce que vous voyez dans le dĂ©veloppement et les machines de test correspondra exactement Ă ce qui va se passer en production si les conditions dâexĂ©cution sont identiques.
Django crĂ©e des migrations pour tout changement dans les modĂšles ou les champs, mĂȘme pour des options qui nâaffectent pas la base de donnĂ©es, car pour lui la seule maniĂšre de reconstruire un champ correctement est dâavoir accĂšs Ă lâhistorique de toutes les modifications ; vous pourriez avoir besoin de ces options lors de migrations de donnĂ©es ultĂ©rieures (par exemple, si vous avez dĂ©fini des rĂšgles de validation particuliĂšres).
Bases de données prises en charge¶
Les migrations sont prises en charge sur tous les moteurs de bases de donnĂ©es livrĂ©es avec Django, ainsi que les bases de donnĂ©es tierces si elles prennent en charge les modifications de schĂ©ma (effectuĂ©es par lâintermĂ©diaire de la classe SchemaEditor).
Toutefois, certaines bases de donnĂ©es ont plus de fonctionnalitĂ©s que dâautres quand il sâagit de migrations de schĂ©ma ; un certain nombre de mises en garde sont rapportĂ©es ci-dessous.
PostgreSQL¶
PostgreSQL est la base de donnĂ©es dans Django qui a le plus de fonctionnalitĂ©s concernant les schĂ©mas ; le seul inconvĂ©nient est que lâajout de colonnes avec des valeurs par dĂ©faut entraĂźne une réécriture complĂšte de la table, avec un temps dâexĂ©cution proportionnel Ă la taille de la table.
Pour cette raison, il est recommandé de toujours créer de nouvelles colonnes avec null=True, car de cette façon elles seront ajoutées immédiatement.
MySQL¶
MySQL ne crĂ©e pas de transactions pour les opĂ©rations de modification de schĂ©ma, ce qui signifie que si une migration ne parvient pas Ă sâappliquer, vous devrez dĂ©faire manuellement les modifications pour essayer de nouveau (il est impossible de revenir Ă un point de sauvegarde antĂ©rieur).
En outre, MySQL réécrit entiĂšrement les tables pour presque toutes les opĂ©rations de schĂ©ma et a gĂ©nĂ©ralement besoin dâun temps dâexĂ©cution proportionnel au nombre de lignes des tables pour ajouter ou supprimer des colonnes. Sur une machine un peu lente, cela peut prendre plus dâune minute par million de lignes ; lâajout de quelques colonnes Ă une table de quelques millions dâentrĂ©es pourrait bloquer votre site pendant plus de dix minutes.
Enfin, MySQL a des tailles limites relativement petites pour la longueur des noms de colonnes, tables et index, ainsi quâune limite sur la taille combinĂ©e de toutes les colonnes quâun index recouvre. Cela signifie que des index qui sont possibles sur dâautres bases de donnĂ©es ne pourront pas toujours ĂȘtre créés avec MySQL.
SQLite¶
SQLite ne gĂšre nativement que trĂšs peu dâopĂ©rations de modifications de schĂ©ma, Django tente donc de les Ă©muler par :
- La crĂ©ation dâune nouvelle table pour le nouveau schĂ©ma 
- La copie des donnĂ©es de lâune Ă lâautre 
- La suppression de lâancienne table 
- Le renommage de la nouvelle table avec le nom de lâancienne table 
Ce processus fonctionne gĂ©nĂ©ralement bien, mais il peut ĂȘtre lent et comporter des anomalies. Il nâest pas recommandĂ© dâutiliser et de faire migrer SQLite dans un environnement de production, sauf si vous ĂȘtes pleinement conscient des risques et des limites ; la prise en charge de Django de cette fonctionnalitĂ© est conçue pour permettre aux dĂ©veloppeurs dâutiliser SQLite sur leurs machines en local pour dĂ©velopper des projets Django moins complexes sans avoir besoin dâune base de donnĂ©es complĂšte.
Procédures¶
Lâutilisation des migrations est simple. Modifiez vos modĂšles - par exemple en ajoutant un champ ou en supprimant un modĂšle - puis exĂ©cutez makemigrations:
$ python manage.py makemigrations
Migrations for 'books':
  0003_auto.py:
    - Alter field author on book
Les modĂšles sont analysĂ©s et comparĂ©s aux versions actuellement contenues dans les fichiers de migration. Puis, un nouveau jeu de migrations est rĂ©digĂ©. Il est chaudement conseillĂ© de lire le rĂ©sultat produit pour voir ce que makemigrations a dĂ©tectĂ© comme changements. Cette commande nâest pas parfaite, et pour des changements complexes, il se peut quâelle nâait pas dĂ©tectĂ© ce que vous attendiez.
Lorsque les nouveaux fichiers de migration sont créés, on peut les appliquer Ă la base de donnĂ©es pour sâassurer quâils fonctionnent correctement :
$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: sessions, admin, messages, auth, staticfiles, contenttypes
  Apply all migrations: books
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Installed 0 object(s) from 0 fixture(s)
Running migrations:
  Applying books.0003_auto... OK
La commande sâexĂ©cute en deux parties. PremiĂšrement, elle synchronise les applications sans migrations (effectuant le mĂȘme processus que faisait anciennement syncdb), puis elle exĂ©cute toute migration qui nâa pas encore Ă©tĂ© appliquĂ©e.
Quand la migration a Ă©tĂ© appliquĂ©e, ajoutez la migration et les modifications des modĂšles dans votre systĂšme de gestion de versions par un seul « commit » ; de cette façon, lorsque dâautres dĂ©veloppeurs (ou votre serveur de production) obtiennent le nouveau code, ils reçoivent en mĂȘme temps les modifications des modĂšles et la migration qui leur correspond.
Si vous souhaitez attribuer un nom Ă©loquent Ă une migration au lieu dâun nom gĂ©nĂ©rĂ© automatiquement, vous pouvez utilisez lâoption --name:
$ python manage.py makemigrations --name changed_my_model your_app_label
ContrÎle de versions¶
Comme les migrations sont stockĂ©es dans le systĂšme de gestion de versions, il peut arriver de temps Ă autre quâun autre dĂ©veloppeur enregistre une migration pour la mĂȘme application en mĂȘme temps que vous, ce qui aboutit Ă deux migrations prĂ©fixĂ©es du mĂȘme numĂ©ro.
Soyez sans crainte, les numĂ©ros servent uniquement comme rĂ©fĂ©rence pour les dĂ©veloppeurs, Django exige seulement que chaque migration soit nommĂ©e diffĂ©remment. Les migrations dĂ©finissent dans leur fichier les autres migrations dont elles dĂ©pendent, y compris les migrations prĂ©cĂ©dentes de la mĂȘme application, il est donc possible de dĂ©tecter lorsquâil y a deux nouvelles migrations pour la mĂȘme application sans prĂ©fĂ©rence dâordre.
Lorsque ceci se produit, Django vous pose la question avec plusieurs options. Sâil pense que câest sans risque, il offre de fusionner automatiquement les deux migrations pour vous. Dans le cas contraire, il vous faudra modifier vous-mĂȘme les migrations, mais ce nâest pas une opĂ©ration difficile et elle est expliquĂ©e plus en dĂ©tails dans Fichiers de migrations ci-dessous.
Dépendances¶
Bien que les migrations sont spĂ©cifiques Ă chaque application, les tables et les relations dĂ©terminĂ©es par les modĂšles sont trop complexes pour ĂȘtre seulement créées pour une application Ă la fois. Lorsque vous crĂ©ez une migration qui nĂ©cessite quâune autre opĂ©ration soit exĂ©cutĂ©e, par exemple lâajout dâune clĂ© ForeignKey de lâapplication livres vers lâapplication auteurs, la migration rĂ©sultante contiendra une dĂ©pendance sur une migration dans auteurs.
Cela signifie que quand vous exĂ©cutez les migrations, la migration de auteurs sâexĂ©cute en premier et crĂ©e la table rĂ©fĂ©rencĂ©e par la clĂ© Ă©trangĂšre, puis la migration qui crĂ©e la colonne ForeignKey peut sâexĂ©cuter et crĂ©er la contrainte. Si cela ne se faisait pas ainsi, la migration essaierait de crĂ©er une colonne ForeignKey sans que la table rĂ©fĂ©rencĂ©e nâexiste et la base de donnĂ©es signalerait une erreur.
Ce comportement de dĂ©pendances affecte la majoritĂ© des opĂ©rations de migration qui sont limitĂ©es Ă une seule application. La restriction Ă une seule application (que ce soit pour makemigrations ou pour migrate) est respectĂ©e dans la mesure du possible, mais ce nâest pas une garantie ; toute autre application concernĂ©e dans lâoptique de la gestion des dĂ©pendances sera Ă©galement impliquĂ©e dans lâopĂ©ration.
Il faut cependant savoir que les applications sans migrations ne peuvent pas dĂ©pendre dâapplications avec migrations, par la nature mĂȘme de lâabsence de migrations. Cela signifie quâil nâest gĂ©nĂ©ralement pas possible dâavoir une application sans migrations qui possĂšde une clĂ© ForeignKey ou un champ ManyToManyField vers une application avec migrations ; cela peut marcher dans certains cas, mais risque bien de finir par des erreurs.
Avertissement
MĂȘme si les choses semblent fonctionner avec des applications sans migrations dĂ©pendant dâapplications avec migrations, il se peut que Django ne produise pas toutes les contraintes de clĂ© Ă©trangĂšre nĂ©cessaires !
Câest particuliĂšrement visible quand on utilise des modĂšles interchangeables (par ex. AUTH_USER_MODEL), car chaque application qui utilise ces modĂšles aura besoin de migrations si vous nâavez pas de chance. Le temps passant, de plus en plus dâapplications tierces possĂ©deront des migrations, mais dans lâintervalle, vous pouvez soit leur ajouter vous-mĂȘme des migrations (en utilisant MIGRATION_MODULES pour stocker ces modules en dehors des modules propres Ă lâapplication, si vous le voulez), soit laisser lâapplication contenant votre modĂšle utilisateur sans migrations.
De plus, tout modĂšle utilisĂ© dans des opĂ©rations RunPython doit possĂ©der des migrations afin que leurs relations Ă dâautres modĂšles puissent ĂȘtre créées convenablement.
Fichiers de migrations¶
Les migrations sont stockĂ©es sous forme de fichiers sur disque nommĂ©s « fichiers de migrations ». Ce ne sont en rĂ©alitĂ© que des fichiers Python normaux avec une structure dâobjets convenue, rĂ©digĂ©e dans un style dĂ©claratif.
Un fichier de migration simple ressemble Ă ceci :
from django.db import migrations, models
class Migration(migrations.Migration):
    dependencies = [("migrations", "0001_initial")]
    operations = [
        migrations.DeleteModel("Tribble"),
        migrations.AddField("Author", "rating", models.IntegerField(default=0)),
    ]
Lorsque Django charge un fichier de migration (sous forme de module Python), Django recherche une sous-classe de django.db.migrations.Migration nommée Migration. Il inspecte ensuite cet objet en cherchant quatre attributs, parmi lesquels deux sont utilisés la plupart du temps :
- dependencies, une liste de migrations dont celle-ci dépend. 
- operations, une liste de classes Operation définissant ce que fait cette migration. 
LâĂ©lĂ©ment central, câest les opĂ©rations ; il sâagit dâun ensemble dâinstructions dĂ©claratives indiquant Ă Django quelles sont les modifications de schĂ©ma quâil doit effectuer. Django les analyse et construit une reprĂ©sentation en mĂ©moire de tous ces changements de schĂ©ma pour toutes les applications, puis utilise cela pour gĂ©nĂ©rer le code SQL qui procĂ©dera aux modifications de schĂ©ma.
Cette structure en mĂ©moire est Ă©galement utilisĂ©e pour calculer les diffĂ©rences entre les modĂšles et lâĂ©tat actuel des migrations ; Django parcourt toutes les modifications dans lâordre en les appliquant Ă un ensemble de modĂšles en mĂ©moire afin dâaboutir Ă lâĂ©tat des modĂšles Ă lâinstant de la derniĂšre exĂ©cution de makemigrations. Il utilise ensuite ces modĂšles pour les comparer Ă ceux qui se trouvent dans les fichiers models.py afin de dĂ©terminer ce qui a changĂ©.
Il est rarement nécessaire de devoir modifier des fichiers de migration à la main, mais il est tout à fait possible de les écrire manuellement en cas de besoin. Certaines des opérations les plus complexes ne sont pas détectables automatiquement et ne sont donc disponibles que si on les écrit manuellement ; il ne faut donc pas avoir peur de modifier les migrations en cas de nécessité.
Champs personnalisés¶
Il nâest pas possible de modifier le nombre de paramĂštres positionnels dans un champ personnalisĂ© dĂ©jĂ migrĂ© sans gĂ©nĂ©rer une exception TypeError. Lâancienne migration appellera la mĂ©thode __init__ modifiĂ©e avec lâancienne signature. Si donc vous avez besoin dâun nouveau paramĂštre, crĂ©ez plutĂŽt un paramĂštre nommĂ© et ajoutez quelque chose comme assert 'nom_du_paramĂštre' in kwargs dans le constructeur.
Gestionnaires de modÚles¶
Si vous le souhaitez, il est possible de sĂ©rialiser les gestionnaires dâobjets dans les migrations pour quâils soient disponibles lors des opĂ©rations RunPython. Cela peut se faire en dĂ©finissant un attribut use_in_migrations sur la classe du gestionnaire :
class MyManager(models.Manager):
    use_in_migrations = True
class MyModel(models.Model):
    objects = MyManager()
Si vous utilisez la fonction from_queryset() pour gĂ©nĂ©rer dynamiquement une classe de gestionnaire, il est nĂ©cessaire dâhĂ©riter de la classe gĂ©nĂ©rĂ©e pour la rendre importable :
class MyManager(MyBaseManager.from_queryset(CustomQuerySet)):
    use_in_migrations = True
class MyModel(models.Model):
    objects = MyManager()
Veuillez vous référer aux notes sur les ModÚles historiques dans les migrations pour connaßtre les implications que cela génÚre.
Ajout de migrations aux applications¶
Lâajout de migrations Ă de nouvelles applications est trĂšs simple, car elles sont prĂ©configurĂ©es pour accepter les migrations ; il suffit dâexĂ©cuter makemigrations aprĂšs avoir effectuĂ© un certain nombre de modifications.
Si lâapplication possĂšde dĂ©jĂ des modĂšles et des tables de base de donnĂ©es et quâelle nâa pas encore de migrations (par exemple parce que vous lâavez créée avec une version prĂ©cĂ©dente de Django), vous allez devoir la convertir en vue de lâutilisation des migrations. Il sâagit dâun procĂ©dĂ© simple :
$ python manage.py makemigrations your_app_label
Cela va crĂ©er une nouvelle migration initiale pour lâapplication. Ensuite, lancez python manage.py migrate --fake-initial, et Django dĂ©tectera quâune migration initiale est prĂ©sente et que les tables quâil doit crĂ©er existent dĂ©jĂ ; il va alors marquer la migration comme dĂ©jĂ appliquĂ©e (sans le drapeau --fake-initial, la commande migrate produirait une erreur car les tables quâelle essayerait de crĂ©er existent dĂ©jĂ ).
Notez que cela ne fonctionne quâĂ deux conditions :
- Les modĂšles nâont pas Ă©tĂ© modifiĂ©s depuis la crĂ©ation des tables correspondantes. Pour que les migrations fonctionnent, vous devez dâabord crĂ©er la migration initiale, puis faire les modifications, car Django compare les modifications aux fichiers de migration, pas Ă la base de donnĂ©es. 
- La base de donnĂ©es nâa pas Ă©tĂ© modifiĂ©e manuellement. Django nâest pas capable de dĂ©tecter que la base de donnĂ©es ne correspond pas aux modĂšles, et au moment oĂč les migrations essaieront de modifier ces tables, vous obtiendrez des erreurs. 
Lâoption --fake-initial a Ă©tĂ© ajoutĂ©e Ă migrate. PrĂ©cĂ©demment, les migrations initiales Ă©taient toujours « pseudo-appliquĂ©es » automatiquement si des tables existantes Ă©taient dĂ©tectĂ©es.
ModÚles historiques¶
Lorsque vous exĂ©cutez des migrations, Django se base sur des versions historiques des modĂšles stockĂ©es dans les fichiers de migration. Si vous rĂ©digez du code Python en utilisant lâopĂ©ration RunPython ou si vous avez des mĂ©thodes allow_migrate sur vos routeurs de base de donnĂ©es, vous serez confrontĂ© Ă ces versions de vos modĂšles.
Comme il nâest pas possible de sĂ©rialiser du code Python arbitraire, ces modĂšles historiques ne possĂ©deront pas de mĂ©thodes personnalisĂ©es que vous auriez pu dĂ©finir. Ils auront cependant les mĂȘmes champs, relations, gestionnaires (pour ceux qui possĂšdent lâattribut use_in_migrations = True) et options Meta (Ă©galement historiques, pouvant donc ĂȘtre diffĂ©rents des Ă©lĂ©ments actuels).
Avertissement
Cela signifie que des mĂ©thodes save() personnalisĂ©es ne seront PAS appelĂ©es pour les objets manipulĂ©s dans les migrations, de la mĂȘme maniĂšre que des constructeurs ou des mĂ©thodes dâinstance personnalisĂ©es ne sont PAS accessibles. Planifiez avec prĂ©caution !
Les rĂ©fĂ©rences Ă des fonctions dans les options de champ telles que upload_to, limit_choices_to et les dĂ©clarations de gestionnaire de modĂšle ayant lâattribut use_in_migrations = True sont sĂ©rialisĂ©es dans les migrations, ce qui fait que ces fonctions et classes doivent ĂȘtre conservĂ©es quelque part dans le code aussi longtemps que des migrations les rĂ©fĂ©rencent. Il sâagit Ă©galement de conserver les champs de modĂšle personnalisĂ©s, car ils sont importĂ©s directement par les migrations.
De plus, les classes de base des modĂšles sont simplement stockĂ©es sous forme de pointeurs, il faut donc toujours conserver ces classes de base quelque part aussi longtemps quâune migration contient une rĂ©fĂ©rence vers elles. Le cĂŽtĂ© positif est que les mĂ©thodes et gestionnaires de ces classes de base hĂ©ritent de façon normale, ce qui fait que si vous avez absolument besoin dây avoir accĂšs, une possibilitĂ© est de les dĂ©placer dans une classe parente.
Considérations lors de la suppression de champs de modÚles¶
Dans le mĂȘme ordre dâidĂ©e que les considĂ©rations sur les « rĂ©fĂ©rences aux fonctions historiques » dans la section prĂ©cĂ©dente, la suppression de champs de modĂšles personnalisĂ©s dâun projet ou dâune application tierce posera un problĂšme si ces champs sont rĂ©fĂ©rencĂ©s dans dâanciennes migrations.
Pour vous assister dans cette situation, Django fournit quelques attributs de champs de modĂšle qui peuvent aider Ă rendre obsolĂštes des champs de modĂšle Ă lâaide de lâ infrastructure des contrĂŽles systĂšmes.
Ajoutez lâattribut system_check_deprecated_details au champ de modĂšle concernĂ© de cette maniĂšre :
class IPAddressField(Field):
    system_check_deprecated_details = {
        'msg': (
            'IPAddressField has been deprecated. Support for it (except '
            'in historical migrations) will be removed in Django 1.9.'
        ),
        'hint': 'Use GenericIPAddressField instead.',  # optional
        'id': 'fields.W900',  # pick a unique ID for your field.
    }
AprĂšs une pĂ©riode dâobsolescence de votre choix (deux versions majeures pour les champs propres Ă Django), modifiez lâattribut system_check_deprecated_details en system_check_removed_details et mettez Ă jour le dictionnaire selon le modĂšle suivant :
class IPAddressField(Field):
    system_check_removed_details = {
        'msg': (
            'IPAddressField has been removed except for support in '
            'historical migrations.'
        ),
        'hint': 'Use GenericIPAddressField instead.',
        'id': 'fields.E900',  # pick a unique ID for your field.
    }
Il faut toujours conserver les méthodes de champ qui lui sont nécessaires pour fonctionner dans le contexte de migrations de base de données, telles que __init__(), deconstruct() et get_internal_type(). Conservez ce champ historisé aussi longtemps que des migrations le référençant existent encore. Par exemple, aprÚs avoir fusionné des migrations et effacé les anciennes, il est alors possible de supprimer complÚtement cet ancien champ.
Migrations de données¶
En plus de modifier le schĂ©ma de base de donnĂ©es, les migrations peuvent aussi ĂȘtre utilisĂ©es pour modifier les donnĂ©es mĂȘmes de la base de donnĂ©es, conjointement avec le schĂ©ma, si vous le souhaitez.
Les migrations qui modifient des donnĂ©es sont gĂ©nĂ©ralement appelĂ©es des « migrations de donnĂ©es » ; il est prĂ©fĂ©rable dâen faire des migrations sĂ©parĂ©es, en parallĂšle des migrations de schĂ©ma.
Django ne sait pas gĂ©nĂ©rer automatiquement des migrations de donnĂ©es Ă votre place, comme il le fait pour les migrations de schĂ©ma, mais il nâest pas trĂšs compliquĂ© de les Ă©crire. Les fichiers de migration dans Django sont composĂ©s dâOperations, et la principale opĂ©ration utilisĂ©e pour les migrations de donnĂ©es est RunPython.
Pour commencer, créez un fichier de migration vide qui constituera votre point de départ (Django place le fichier au bon endroit, suggÚre un nom et ajoute les dépendances pour vous) :
python manage.py makemigrations --empty yourappname
Puis, ouvrez le fichier ; il devrait ressembler Ă quelque chose comme ceci :
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
    dependencies = [
        ('yourappname', '0001_initial'),
    ]
    operations = [
    ]
Tout ce quâil vous reste Ă faire est de crĂ©er une nouvelle fonction et de demander Ă RunPython de lâappeler. RunPython sâattend Ă un objet exĂ©cutable en paramĂštre qui accepte lui-mĂȘme deux paramĂštres : le premier est un registre dâapplications contenant les versions historisĂ©es de tous les modĂšles qui y sont chargĂ©s afin de correspondre Ă lâendroit oĂč se situe la migration dans lâhistorique, et le second est une classe SchemaEditor permettant dâeffectuer manuellement des modifications de schĂ©ma de la base de donnĂ©es (mais prenez garde, de telles modifications pourraient embrouiller lâauto-dĂ©tecteur de migrations !).
Ăcrivons une migration simple qui remplit notre nouveau champ name avec les valeurs combinĂ©es de first_name et last_name (nous sommes retombĂ©s sur nos pieds et avons rĂ©alisĂ© que tout le monde nâa pas forcĂ©ment un nom et un prĂ©nom). Tout ce que nous avons Ă faire est dâutiliser le modĂšle historique et de parcourir chaque ligne :
# -*- coding: utf-8 -*-
from django.db import models, migrations
def combine_names(apps, schema_editor):
    # We can't import the Person model directly as it may be a newer
    # version than this migration expects. We use the historical version.
    Person = apps.get_model("yourappname", "Person")
    for person in Person.objects.all():
        person.name = "%s %s" % (person.first_name, person.last_name)
        person.save()
class Migration(migrations.Migration):
    dependencies = [
        ('yourappname', '0001_initial'),
    ]
    operations = [
        migrations.RunPython(combine_names),
    ]
Une fois que câest fait, il suffit de lancer normalement python manage.py migrate et la migration de donnĂ©es sera exĂ©cutĂ©e comme toute autre migration.
Il est possible de passer un second objet exĂ©cutable Ă RunPython pour exĂ©cuter toute logique adĂ©quate dans le cas dâune migration inverse. Si cet objet est omis, la migration inverse gĂ©nĂ©rera une exception, le cas Ă©chĂ©ant.
AccĂšder aux modĂšles dâautres applications¶
Lorsque vous Ă©crivez une fonction appelĂ©e par RunPython et qui utilise des modĂšles issus dâapplications autres que celle dans laquelle la migration est situĂ©e, lâattribut dependencies de la migration doit inclure la derniĂšre migration de chaque application qui est en cause, sinon vous pouvez obtenir une erreur semblable Ă : LookupError: Aucune application installĂ©e pour 'myappname' lorsque vous utilisez apps.get_model() pour essayer de rĂ©cupĂ©rer le modĂšle dans la fonction appelĂ©e par RunPython.
Dans lâexemple suivant, nous avons une migration dans app1 qui a besoin dâutiliser des modĂšles dans app2. Nous ne sommes pas prĂ©occupĂ©s par les dĂ©tails de move_m1 mis Ă part que cette fonction aura besoin dâaccĂ©der Ă des modĂšles des deux applications. Par consĂ©quent, nous avons ajoutĂ© une dĂ©pendance qui spĂ©cifie la derniĂšre migration de app2
class Migration(migrations.Migration):
    dependencies = [
        ('app1', '0001_initial'),
        # added dependency to enable using models from app2 in move_m1
        ('app2', '0004_foobar'),
    ]
    operations = [
        migrations.RunPython(move_m1),
    ]
Migrations avancées¶
Si vous ĂȘtes intĂ©ressĂ© aux opĂ©rations de migration plus avancĂ©es ou que vous voulez pouvoir Ă©crire votre propre opĂ©ration, consultez la rĂ©fĂ©rence des opĂ©rations de migration et le guide pratique sur lâĂ©criture de migrations.
Fusion de migrations¶
Il ne faut pas craindre de crĂ©er autant de migrations que nĂ©cessaire, ce nâest pas un problĂšme. Le code de migration est optimisĂ© pour traiter des centaines de migrations Ă la fois sans trop de lenteurs. Cependant, il peut arriver un moment oĂč lâon souhaite rĂ©duire un grand nombre de migrations Ă juste quelques-unes, et câest lĂ que la fusion des migrations intervient.
La fusion est lâacte de rĂ©duire un ensemble existant de nombreuses migrations Ă une seule (ou parfois quelques-unes) qui reprĂ©sente toujours les mĂȘmes changements.
Django opĂšre cela en prenant toutes les migrations existantes, extrayant leurs opĂ©rations en les plaçant toutes Ă la suite, puis exĂ©cutant un optimiseur pour essayer de rĂ©duire au maximum cette liste dâopĂ©rations. Par exemple, il sait que CreateModel et DeleteModel sâannulent lâune lâautre et que AddField peut ĂȘtre intĂ©grĂ©e dans CreateModel.
Une fois que la suite dâopĂ©rations a Ă©tĂ© rĂ©duite au minimum, Django Ă©crit le rĂ©sultat dans une nouvel ensemble de fichiers de migration initiale. Ce nombre minimum dĂ©pend de la quantitĂ© de dĂ©pendances relatives entre les modĂšles et de la prĂ©sence dâopĂ©rations RunSQL ou RunPython (qui ne peuvent pas subir dâoptimisation).
Dans ces fichiers, il est indiquĂ© quâils remplacent les migrations fusionnĂ©es prĂ©cĂ©dentes, ce qui signifie quâils peuvent coexister avec les anciens fichiers de migration ; Django choisit intelligemment les fichiers Ă prendre en compte en fonction de la position actuelle dans lâhistorique de migration. Si un projet nâa pas encore complĂštement appliquĂ© un ensemble de migrations qui a Ă©tĂ© fusionnĂ©, Django continue dâutiliser ces anciennes migrations jusquâau moment de la fusion, aprĂšs quoi il se rattache Ă lâhistorique fusionnĂ©, tandis que de nouvelles installations du projet vont directement utiliser la nouvelle migration fusionnĂ©e et laisser de cĂŽtĂ© les anciennes.
Cela permet de fusionner des migrations sans perturber des systĂšmes actuellement en production qui ne sont pas encore totalement Ă jour. Le processus recommandĂ© est de fusionner, de conserver les anciens fichiers, de valider et publier le rĂ©sultat, dâattendre jusquâĂ ce que tous les systĂšmes soient mis Ă jour avec la nouvelle version (ou dans le cas dâune application rĂ©utilisable, sâassurer que les utilisateurs mettent Ă jour en suivant les versions sans en sauter), puis de supprimer les anciens fichiers, de valider et de publier une seconde version.
La commande qui se charge de tout ceci est squashmigrations. Il suffit de lui transmettre lâĂ©tiquette dâapplication et le nom de la migration jusquâĂ laquelle vous souhaitez fusionner, et elle se mettra au travail :
$ ./manage.py squashmigrations myapp 0004
Will squash the following migrations:
 - 0001_initial
 - 0002_some_change
 - 0003_another_change
 - 0004_undo_something
Do you wish to proceed? [yN] y
Optimizing...
  Optimized from 12 operations to 7 operations.
Created new squashed migration /home/andrew/Programs/DjangoTest/test/migrations/0001_squashed_0004_undo_somthing.py
  You should commit this migration but leave the old ones in place;
  the new migration will be used for new installs. Once you are sure
  all instances of the codebase have applied the migrations you squashed,
  you can delete them.
Sachez que les interdĂ©pendances de modĂšles Django peuvent devenir vraiment complexes et la fusion peut aboutir Ă des migrations qui ne peuvent pas ĂȘtre exĂ©cutĂ©es ; il peut soit y avoir un problĂšme dâoptimisation (auquel cas vous pouvez essayer une nouvelle fois avec lâoption --no-optimize, mais il serait aussi judicieux de signaler le problĂšme), soit un problĂšme dâerreur CircularDependencyError, et dans ce cas, vous pouvez le rĂ©soudre manuellement.
Pour rĂ©soudre manuellement une erreur CircularDependencyError, sĂ©parez lâune des clĂ©s Ă©trangĂšres de la boucle de dĂ©pendances circulaires dans une migration distincte, puis dĂ©placez la dĂ©pendance sur lâautre application qui la contient. Si vous hĂ©sitez, examinez comment makemigrations sâoccupe de ce problĂšme lorsquâon lui demande de crĂ©er de toutes nouvelles migrations Ă partir de vos modĂšles. Dans une version future de Django, squashmigrations sera mise Ă jour pour quâelle puisse rĂ©soudre ces erreurs par elle-mĂȘme.
AprĂšs avoir fusionnĂ© les migrations, ajoutez la migration rĂ©sultante en parallĂšle Ă celles quâelle remplace et distribuez cette modification Ă toutes les instances en production de votre projet, en prenant soin dâexĂ©cuter chaque fois migrate pour enregistrer la modification dans la base de donnĂ©es.
Quand cela a été fait, vous devez alors faire passer la migration fusionnée vers une migration initiale normale en :
- supprimant tous les fichiers de migration quâelle remplace ; 
- enlevant le paramĂštre replaces dans la classe Migration de la migration fusionnĂ©e (câest ce qui permet Ă Django de savoir quâil sâagit dâune migration fusionnĂ©e). 
Note
AprĂšs avoir créé une migration fusionnĂ©e, vous ne pouvez pas refusionner celle-ci avant dâavoir effectuĂ© la transition complĂšte vers une migration normale.
Sérialisation de valeurs¶
Les migrations sont de simples fichiers Python contenant les anciennes dĂ©finitions de vos modĂšles. Pour pouvoir les Ă©crire, Django doit donc prendre lâĂ©tat actuel des modĂšles et les sĂ©rialiser dans un fichier.
Bien que Django puisse sĂ©rialiser la plupart des objets, il y en a certains qui ne peuvent simplement pas ĂȘtre sĂ©rialisĂ©s en une reprĂ©sentation Python valide. Il nâexiste pas de standard Python permettant Ă une valeur dâĂȘtre retransformĂ©e en code (repr() ne fonctionne quâavec des valeurs basiques et ne dĂ©finit pas de chemins dâimportation).
Django est capable de sérialiser ce qui suit :
- int, long, float, bool, str, unicode, bytes, None
- list, set, tuple, dict
- Instances datetime.date, datetime.time et datetime.datetime (y compris celles qui contiennent un fuseau horaire) 
- Instances decimal.Decimal 
- Tous les champs Django 
- Toute rĂ©fĂ©rence de fonction ou de mĂ©thode (par ex. datetime.datetime.today) (doit ĂȘtre dĂ©finie au niveau principal du module) 
- Toute rĂ©fĂ©rence de classe (doit ĂȘtre dĂ©finie au niveau principal du module) 
- Tout objet comportant une méthode deconstruct() (voir ci-dessous) 
La prise en charge de la sérialisation des objets datetime avec fuseau horaire a été ajoutée.
Les Ă©lĂ©ments suivants ne peuvent ĂȘtre sĂ©rialisĂ©s par Django quâen Python 3 :
- MĂ©thodes non liĂ©es utilisĂ©es depuis lâintĂ©rieur du corps de la classe (voir ci-dessous) 
Django ne peut pas sérialiser :
- Les classes imbriquées 
- Des instances de classe arbitraires (par ex. MaClasse(4.3, 5.7)) 
- Les fonctions lambdas 
Comme __qualname__ nâa Ă©tĂ© introduit que dans Python 3, Django ne peut sĂ©rialiser lâexemple ci-dessous (une mĂ©thode non liĂ©e utilisĂ©e depuis lâintĂ©rieur du corps de la classe) quâavec Python 3 ; en Python 2, la sĂ©rialisation de cette rĂ©fĂ©rence Ă©chouera :
class MyModel(models.Model):
    def upload_to(self):
        return "something dynamic"
    my_file = models.FileField(upload_to=upload_to)
Si vous utilisez Python 2, il est recommandĂ© de placer les mĂ©thodes pour upload_to et dâautres paramĂštres semblables qui acceptent des objets exĂ©cutables (par ex. default) dans le corps du module principal, plutĂŽt que dans le corps dâune classe.
Ajout dâune mĂ©thode deconstruct()¶
Vous pouvez permettre Ă Django de sĂ©rialiser vos propres instances de classe personnalisĂ©es en dĂ©finissant une mĂ©thode deconstruct() pour la classe. Elle nâaccepte pas de paramĂštres et doit renvoyer un tuple de trois Ă©lĂ©ments (path, args, kwargs):
- path doit contenir le chemin Python vers la classe, avec le nom de la classe inclus en dernier (par exemple, monapp.quelque_chose.MaClasse). Si la classe nâest pas dĂ©finie au premier niveau du module, elle ne peut pas ĂȘtre sĂ©rialisĂ©e. 
- args doit ĂȘtre une liste de paramĂštres positionnels Ă passer Ă la mĂ©thode __init__ de la classe. Tous les Ă©lĂ©ments de cette liste doivent ĂȘtre eux-mĂȘmes sĂ©rialisables. 
- kwargs doit ĂȘtre un dictionnaire de paramĂštres nommĂ©s Ă passer Ă la mĂ©thode __init__ de la classe. Toutes ses valeurs doivent ĂȘtre elles-mĂȘmes sĂ©rialisables. 
Note
Cette valeur de renvoi est différente de la méthode deconstruct() des champs personnalisés qui renvoie un tuple de quatre éléments.
Django Ă©crit la valeur sous forme dâinstanciation de la classe avec les paramĂštres donnĂ©s, de la mĂȘme façon quâil Ă©crit les rĂ©fĂ©rences aux champs Django.
Pour Ă©viter quâune nouvelle migration soit créée lors de chaque exĂ©cution de makemigrations, vous devriez aussi ajouter une mĂ©thode __eq__() Ă la classe dĂ©corĂ©e. Cette fonction sera appelĂ©e par le systĂšme des migrations de Django pour dĂ©tecter dâĂ©ventuels changements dâĂ©tat.
Pour autant que tous les paramĂštres passĂ©s au constructeur de la classe sont eux-mĂȘme sĂ©rialisables, vous pouvez utiliser le dĂ©corateur de classe @deconstructible se trouvant dans django.utils.deconstruct pour ajouter la mĂ©thode deconstruct():
from django.utils.deconstruct import deconstructible
@deconstructible
class MyCustomClass(object):
    def __init__(self, foo=1):
        self.foo = foo
        ...
    def __eq__(self, other):
        return self.foo == other.foo
Ce dĂ©corateur ajoute la logique nĂ©cessaire pour capturer et prĂ©server les paramĂštres lors de leur transmission au constructeur, puis renvoie ces mĂȘmes paramĂštres lorsque deconstruct() est appelĂ©e.
Prise en charge de Python 2 et 3¶
Dans lâoptique de gĂ©nĂ©rer des migrations qui prennent en charge Ă la fois Python 2 et 3, toutes les chaĂźnes de texte littĂ©ral dans vos modĂšles et champs (par ex. verbose_name, related_name, etc.) doivent ĂȘtre des chaĂźnes qui restent toujours soit des chaĂźnes dâoctets, soit des chaĂźnes de texte (unicode), que ce soit avec Python 2 ou 3 (au lieu de reprĂ©senter des octets avec Python 2 et du texte avec Python 3, ce qui correspond Ă la situation par dĂ©faut pour les chaĂźnes littĂ©rales non marquĂ©es spĂ©cialement). Sinon, lâexĂ©cution de makemigrations avec Python 3 risque de produire de nouvelles migrations bizarres qui convertissent tous ces attributs textuels en texte.
La maniĂšre la plus simple de faire cela est de suivre les conseils donnĂ©s dans le guide de migration vers Python 3 et de sâassurer que tous vos modules commencent par from __future__ import unicode_literals afin que toutes les chaĂźnes littĂ©rales soient toujours de lâunicode, quelle que soit la version de Python. Lorsque vous ajoutez cela Ă une application possĂ©dant dĂ©jĂ des migrations gĂ©nĂ©rĂ©es avec Python 2, le prochain lancement de makemigrations avec Python 3 va probablement gĂ©nĂ©rer de multiples changements dans la mesure oĂč tous les attributs de type chaĂźne dâoctets sont convertis en chaĂźnes de texte ; câest normal et ne devrait se produire quâune seule fois.
Prendre en charge plusieurs versions de Django¶
Si vous ĂȘtes responsable dâune application tierce qui contient des modĂšles, vous devrez peut-ĂȘtre fournir des migrations qui prennent en charge plusieurs versions de Django. Dans ce cas, vous devez toujours exĂ©cuter makemigrations avec le plus bas niveau de version de Django vous souhaitez prendre en charge.
Le systĂšme de migrations maintiendra la compatibilitĂ© ascendante selon la mĂȘme politique que le reste de Django, afin que les fichiers de migration gĂ©nĂ©rĂ©es sur Django X.Y devraient fonctionner sans modification sur Django X.Y+1. Cependant, le systĂšme des migrations ne promet pas de compatibilitĂ© descendante. De nouvelles fonctionnalitĂ©s peuvent ĂȘtre ajoutĂ©es, et les fichiers de migration gĂ©nĂ©rĂ©s avec les nouvelles versions de Django pourront ne pas fonctionner sur les anciennes versions.
Mise à jour à partir de South¶
Si vous avez dĂ©jĂ des migrations existantes créées avec South, le processus de mise Ă niveau vers lâutilisation de django.db.migrations est relativement simple :
- Assurez-vous que toutes les installations sont totalement Ă jour avec les migrations actuelles. 
- Enlevez 'south' du réglage INSTALLED_APPS. 
- Supprimez tous les fichiers de migration (numérotés), sauf le répertoire des migrations et le fichier __init__.py. Prenez soin de supprimer également les fichiers .pyc. 
- Exécutez python manage.py makemigrations. Django devrait détecter les répertoires de migrations vides et créer de nouvelles migrations initiales dans le nouveau format. 
- Exécuter python manage.py migrate --fake-initial. Django verra que les tables pour les migrations initiales existent déjà et les marquera comme appliquées sans les exécuter (Django ne contrÎle pas que les schémas des tables correspondent à vos modÚles, mais simplement que les noms de table existent). 
Et câest tout ! La seule complication peut provenir de dĂ©pendances circulaires de clĂ©s Ă©trangĂšres ; dans ce cas, makemigrations pourrait produire plus dâune migration initiale et vous devrez donc ensuite toutes les marquer comme appliquĂ©es en utilisant :
python manage.py migrate --fake yourappnamehere
Lâoption --fake-initial a Ă©tĂ© ajoutĂ©e Ă migrate; prĂ©cĂ©demment, les migrations initiales Ă©taient toujours « pseudo-appliquĂ©es » automatiquement si des tables existantes Ă©taient dĂ©tectĂ©es.
BibliothÚques / applications tierces¶
Si vous ĂȘtes le mainteneur dâune bibliothĂšque ou dâune application tierce, et que vous souhaitez prendre en charge Ă la fois les migrations South (pour Django 1.6 et prĂ©cĂ©dentes versions) et les migrations Django (Ă partir de Django 1.7), il est possible de conserver deux jeux de migrations parallĂšles dans lâapplication, chacune dans son format.
Pour contribuer à cela, South 1.0 va automatiquement et premiÚrement rechercher des migrations au format South dans un répertoire south_migrations avant de regarder dans migrations, ce qui signifie que les projets des utilisateurs utiliseront les bonnes migrations de maniÚre transparente, pour autant que vous placiez les migrations South dans un répertoire nommé south_migrations et les migrations Django dans le répertoire migrations.
Vous trouverez de plus amples informations dans les notes de publication de South 1.0.
Voir aussi
- La référence des opérations de migration
- Documente lâAPI des opĂ©rations de schĂ©ma, les opĂ©rations spĂ©ciales ainsi que lâĂ©criture de ses propres opĂ©rations. 
- Le guide pratique sur lâĂ©criture de migrations
- PrĂ©sente la façon de structurer et dâĂ©crire des migrations de base de donnĂ©es pour diffĂ©rents scĂ©narios auxquels vous pourriez ĂȘtre confrontĂ©s. 
 
          