J'ai effectué une migration qui a ajouté une nouvelle table et je souhaite la restaurer et supprimer la migration, sans créer de nouvelle migration.
Comment fait-on ça? Existe-t-il une commande permettant de rétablir la dernière migration et puis-je simplement supprimer le fichier de migration?
Vous pouvez revenir en migrant vers la migration précédente.
Par exemple, si vos deux dernières migrations sont:
0010_previous_migration
0011_migration_to_revert
Ensuite, vous feriez:
./manage.py migrate my_app 0010_previous_migration
Vous pouvez ensuite supprimer la migration 0011_migration_to_revert
.
Si vous utilisez Django 1.8+, vous pouvez afficher les noms de toutes les migrations avec
./manage.py showmigrations my_app
Pour inverser toutes les migrations d'une application, vous pouvez exécuter:
./manage.py migrate my_app zero
La réponse d'Alasdair couvre l'essentiel
./manage.py showmigrations
migrate
en utilisant le nom de l'application et le nom de la migrationMais il convient de souligner que toutes les migrations peuvent ne peuvent pas être inversées. Cela se produit si Django n’a pas de règle pour inverser la tendance. Pour la plupart des modifications que vous avez effectuées automatiquement par ./manage.py makemigrations
, l'inversion sera possible. Cependant, les scripts personnalisés devront être écrits à la fois en avant et en arrière, comme décrit dans l'exemple ci-dessous:
https://docs.djangoproject.com/fr/1.9/ref/migration-operations/
Si vous avez effectué une opération RunPython
, vous souhaitez peut-être simplement annuler la migration sans écrire un script d'inversion logiquement rigoureux. Le piratage rapide suivant de l'exemple dans la documentation (lien ci-dessus) le permet, laissant la base de données dans l'état où elle se trouvait après l'application de la migration, même après son inversion.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from Django.db import migrations, models
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).bulk_create([
Country(name="USA", code="us"),
Country(name="France", code="fr"),
])
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(forwards_func, lambda apps, schema_editor: None),
]
Cela fonctionne pour Django 1.8, 1.9
Mise à jour: Un meilleur moyen d'écrire ceci serait de remplacer lambda apps, schema_editor: None
par migrations.RunPython.noop
dans l'extrait de code ci-dessus. Ce sont tous deux fonctionnellement la même chose. (crédit aux commentaires)
L'autre chose que vous pouvez faire est de supprimer la table créée manuellement.
Parallèlement à cela, vous devrez supprimer ce fichier de migration particulier. De plus, vous devrez supprimer cette entrée particulière de la table Django-migrations (probablement la dernière dans votre cas) qui correspond à cette migration particulière.
Voici ma solution, car la solution ci-dessus ne couvre pas vraiment le cas d'utilisation, lorsque vous utilisez RunPython
.
Vous pouvez accéder à la table via l’ORM avec
from Django.db.migrations.recorder import MigrationRecorder
>>> MigrationRecorder.Migration.objects.all()
>>> MigrationRecorder.Migration.objects.latest('id')
Out[5]: <Migration: Migration 0050_auto_20170603_1814 for model>
>>> MigrationRecorder.Migration.objects.latest('id').delete()
Out[4]: (1, {u'migrations.Migration': 1})
Vous pouvez donc interroger les tables et supprimer les entrées pertinentes pour vous. De cette façon, vous pouvez modifier en détail. Avec les migrations RynPython
, vous devez également vous occuper des données ajoutées/modifiées/supprimées. L'exemple ci-dessus montre uniquement comment vous accédez à la table via Djang ORM.
Je l'ai fait dans 1.9.1 (pour supprimer la dernière ou la dernière migration créée):
rm <appname>/migrations/<migration #>*
exemple: rm myapp/migrations/0011*
connecté à la base de données et exécuté ce SQL (postgres dans cet exemple)
delete from Django_migrations where name like '0011%';
J'ai ensuite pu créer de nouvelles migrations commençant par le numéro de migration que je venais de supprimer (dans ce cas, 11).
Alasdair a répondu à la première partie, comment "annuler la migration". Je vais répondre:
... supprimer la migration, sans créer une nouvelle migration?
TL; DR: Vous pouvez supprimer quelques dernières migrations inversées (confuses) et en créer une nouvelle après avoir réparé les modèles. Vous pouvez utiliser d'autres moyens pour configurer afin de ne pas créer de tableau à l'aide de la commande migrate, mais la dernière migration doit être créée pour correspondre aux modèles actuels.
La migration "problématique" qui a créé une table indésirable est provoquée par une nouvelle classe Model que vous avez ajoutée.
Pourquoi quelqu'un ne veut-il pas avoir une table? Comment le résoudre?
A) Aucune table de ce type ne devrait exister dans aucune base de données sur aucune machine et aucune condition
class Meta: abstract = True
B) La table est créée rarement, par quelque chose d'autre ou manuellement d'une manière spéciale.
class Meta: managed = False
C) Le tableau est utilisé uniquement sur certaines machines (par exemple, en cours de développement).
class Meta: managed = some_switch
conditionnel.D) Le projet utilise plusieurs bases de données dans settings.DATABASES
allow_migrate
afin de différencier les bases de données sur lesquelles la table peut ou non être créée.(Ai-je oublié quelque chose? Je suppose que tout ce qui a fonctionné pour vous, seule la table doit être créée. Par exemple, un bogue dans l'option proxy d'un modèle peut être exclu.)
La migration est créée dans les cas B), C), D) avec Django 1.8 et dans tous les cas ABCD avec Django 1.9+, mais appliquée à la base de données uniquement dans les cas appropriés ou peut-être jamais, si nécessaire. Les migrations sont nécessaires pour exécuter des tests depuis Django 1.8. L’état actuel complet et pertinent est enregistré par les migrations même pour les modèles avec managé = False dans Django 1.9+ afin de pouvoir créer une ForeignKey entre des modèles managés/non managés ou pour rendre le modèle géré = True ultérieurement. (Cette question a été écrite à l’époque de l'intégration de Django 1.8. Tout ici devrait être valable pour les versions comprises entre 1.8 et 1.11.)
Si vous rencontrez des problèmes lors de la restauration de la migration et que vous l’avez perturbée, vous pouvez effectuer des migrations fake
.
./manage.py migrate <name> --ignore-ghost-migrations --merge --fake
Pour Django version <1.4, cela créera une entrée dans la table south_migrationhistory
, vous devez supprimer cette entrée.
Vous pourrez désormais revenir facilement à la migration.
PS: Je suis resté bloqué pendant un bon bout de temps. Effectuer une fausse migration, puis revenir en arrière m'a aidé.