HOWTO · Django

Annulation de la dernière migration de base de données dans Django

Cet article vous explique comment revenir à la dernière migration de base de données dans Django.

Sur cette page

Pour annuler la dernière migration Django appliquée, exécutez python manage.py migrate <app_label> <migration_name> et choisissez la migration qui doit rester appliquée, généralement celle qui précède immédiatement la migration à inverser. Django inverse les migrations postérieures à cette cible pour l’application indiquée. Utilisez d’abord showmigrations pour vérifier l’état actuel de l’application. Sauvegardez les données importantes avant toute annulation : l’inversion d’opérations sur le schéma peut entraîner une perte de données et certaines opérations sont irréversibles.

Annuler jusqu’à une migration précise

Utilisez python manage.py showmigrations <app_label> pour afficher les migrations d’une application. Les migrations appliquées portent la marque [X] ; celles qui ne le sont pas portent [ ]. Le libellé de l’application est le nom Django utilisé dans les commandes de migration, et le nom de migration correspond à la partie du nom de fichier qui précède .py.

Par exemple, supposons que blog possède les migrations 0001_initial, 0002_add_author et 0003_remove_legacy_field, et qu’elles soient toutes les trois appliquées. Pour annuler uniquement 0003_remove_legacy_field, choisissez 0002_add_author comme cible : python manage.py migrate blog 0002_add_author. La cible désigne l’état final des migrations à conserver, et non celle à annuler. Django inverse 0003 ainsi que toute migration ultérieure appliquée à blog. Un préfixe numérique comme 0002 peut identifier la cible, mais son nom complet rend le choix plus explicite.

Exécutez la commande dans l’environnement du projet où manage.py peut charger les paramètres et la connexion à la base de données appropriés. Vérifiez l’application cible et la base de données avant de continuer, surtout si plusieurs environnements sont configurés.

Exécutez cet extrait Python pour afficher une commande correspondant à une application et à une cible :

Le code et les libellés ou sorties affichés dans cette section restent en anglais.

app_label = "blog"
target = "0002_add_author"
print(f"python manage.py migrate {app_label} {target}")
python manage.py migrate blog 0002_add_author

L’extrait formate uniquement la commande ; exécutez la commande affichée depuis votre projet Django pour modifier l’état de la base de données.

Annuler toutes les migrations d’une application

Pour inverser toutes les migrations appliquées d’une application, utilisez python manage.py migrate <app_label> zero, par exemple python manage.py migrate blog zero. Ici, zero désigne l’état où aucune migration de cette application n’a encore été appliquée. Django inverse l’historique des migrations de l’application dans l’ordre inverse. Cela ne signifie pas « annuler la dernière migration » et peut supprimer des tables ou des colonnes, ainsi que leurs données. Examinez la liste des migrations de l’application et sauvegardez la base de données avant d’utiliser cette cible.

Pour inverser plusieurs migrations sans toutes les annuler, indiquez une migration antérieure comme cible. Django remonte depuis l’état actuellement appliqué jusqu’à cette cible. Les migrations d’autres applications ne sont pas sélectionnées simplement parce qu’elles sont plus récentes dans l’historique global du projet, mais les dépendances peuvent influer sur le plan. Lisez les opérations prévues par Django avant de confirmer une modification en production.

Comprendre la réversibilité et la perte de données

Django peut inverser une opération si la migration définit une opération inverse ou si Django peut en déduire une. Certaines opérations, comme la suppression de données par une opération Python personnalisée dépourvue de fonction inverse, ne peuvent pas être reconstituées. Tenter d’inverser une telle migration déclenche IrreversibleError. Examinez les opérations de la migration et le message d’erreur complet pour déterminer quelle étape ne possède pas de chemin inverse ; ne supposez pas que restaurer un ancien fichier de migration rend ses effets sur la base réversibles.

Même une modification de schéma réversible peut entraîner une perte de données. Par exemple, inverser la suppression d’un champ ne peut pas restaurer les valeurs perdues lors de cette suppression. Avant toute annulation, sauvegardez la base de données, vérifiez s’il faut suspendre les écritures de l’application et demandez-vous si une correction en avant serait plus sûre. En production, répétez la procédure sur une sauvegarde récente et vérifiez le plan de récupération avant de modifier la base de données active.

Git gère les fichiers sources des migrations, tandis que migrate modifie l’état de la base de données. Extraire ou rétablir un commit Git n’annule pas à lui seul une migration dans la base de données. Restaurer séparément les fichiers de migration peut aussi créer une incohérence entre le code et l’historique des migrations enregistré. Utilisez donc les commandes de migration Django pour l’opération sur la base de données et coordonnez séparément toute récupération du code.

Vérifier l’état de la base de données

Une fois la commande terminée, exécutez de nouveau python manage.py showmigrations <app_label>. Vérifiez que la cible voulue et les migrations antérieures portent la marque [X], et que les migrations inversées portent [ ]. Cela indique l’état des migrations enregistré par Django ; cela ne vérifie pas toutes les attentes concernant les données de l’application et ne prouve pas que le schéma et les données sont sains. Vérifiez le comportement de l’application concernée et, au besoin, inspectez la base de données ou exécutez des contrôles propres au projet.

Si les marques ne correspondent pas à la cible voulue, arrêtez-vous avant de lancer une autre annulation. Vérifiez que vous êtes connecté à la base de données prévue, examinez la sortie de la commande et les dépendances entre migrations, puis choisissez la prochaine opération en fonction de l’état réellement enregistré.