web-dev-qa-db-fra.com

django revenir la dernière migration

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?

291
Ronen Ness

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
535
Alasdair

La réponse d'Alasdair couvre l'essentiel

  • Identifiez les migrations souhaitées par ./manage.py showmigrations
  • migrate en utilisant le nom de l'application et le nom de la migration

Mais 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/

Comment faire un renversement sans opération

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)

27
AlanSE

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.

8
sprksh

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.

6
Özer S.

Je l'ai fait dans 1.9.1 (pour supprimer la dernière ou la dernière migration créée):

  1. rm <appname>/migrations/<migration #>*

    exemple: rm myapp/migrations/0011*

  2. 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).

5
MIkee

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

  • When: Il s'agit d'un modèle de base d'un autre modèle, créé uniquement pour l'héritage du modèle.
  • Solution: Set class Meta: abstract = True

B) La table est créée rarement, par quelque chose d'autre ou manuellement d'une manière spéciale.

  • Solution: Utilisez class Meta: managed = False
    La migration est créée, mais n’est jamais utilisée, seulement dans les tests. Le fichier de migration est important, sinon les tests de base de données ne peuvent pas être exécutés à partir d'un état initial reproductible.

C) Le tableau est utilisé uniquement sur certaines machines (par exemple, en cours de développement).

  • Solution: Déplacez le modèle dans une nouvelle application ajoutée à INSTALLED_APPS uniquement dans des conditions spéciales ou utilisez un class Meta: managed = some_switch conditionnel.

D) Le projet utilise plusieurs bases de données dans settings.DATABASES

  • Solution : Ecrire un Routeur de base de données avec la méthode 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.)

2
hynekcer

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é.

0
Pransh Tiwari