Quelle est l'approche recommandée pour réinitialiser l'historique des migrations à l'aide de Django South?

153

J'ai accumulé pas mal de migrations en utilisant South (0.7) et Django (1.1.2) qui commencent à prendre pas mal de temps dans mes tests unitaires. Je voudrais réinitialiser la ligne de base et démarrer une nouvelle série de migrations. J'ai examiné la documentation du sud , effectué la recherche habituelle de Google / Stackoverflow (par exemple "historique de migration de django south (réinitialiser OU supprimer OU supprimer)") et je n'ai rien trouvé d'évident.

Une approche que j'ai envisagée consisterait à "recommencer" en "supprimant" Sud ou en "effaçant" l'historique manuellement (par exemple, effacer la table de base de données, supprimer les fichiers de migration du directeur des migrations) et simplement réexécuter,

./manage.py schemamigration southtut --initial

Donc, si quelqu'un a déjà fait cela avant et a quelques conseils / suggestions, ils seraient grandement appréciés.

Glenn Snyder
la source
parfois vous devez ajouter manuellement __init__.pyàappname/migrations
laike9m
2
Comment réinitialiser les migrations dans 1.7 (avec la migration intégrée)?
Timo
1
@Timo: docs.djangoproject.com/en/dev/topics/migrations/ ... pourrait être une approche. Vous pouvez aussi simplement supprimer vos migrations / répertoires et rééditer ./manage.py makemigrationsmais de mauvaises choses se produiront si vous ne démarrez pas à partir d'une nouvelle base de données ...
Jocelyn delalande
Je pense que squashmigrationsc'est la bonne réponse
Julio Marins

Réponses:

121

EDIT - Je mets un commentaire ci-dessous en haut de ceci car il est important de le lire avant la> réponse acceptée qui suit @andybak

@Dominique: Vos conseils concernant manage.py reset south sont dangereux et peuvent détruire la base de données si des applications tierces utilisent South dans le projet, comme indiqué par @thnee ci-dessous. Étant donné que votre réponse a tellement de votes positifs, j'apprécierais vraiment que vous puissiez la modifier et ajouter au moins un avertissement à ce sujet, ou (encore mieux) la changer pour refléter l'approche @hobs (ce qui est tout aussi pratique, mais ne le fait pas affectent d'autres applications) - merci! - chrisv 26 mars 13 à 9:09

La réponse acceptée suit ci-dessous:

Tout d'abord, une réponse de l'auteur du Sud :

Tant que vous prenez soin de le faire sur tous les déploiements simultanément, cela ne devrait pas poser de problème. Personnellement, je ferais:

    rm -r appname/migrations/ 
    ./manage.py reset south 
    ./manage.py convert_to_south appname 

(Notez que la reset southpartie « » efface les enregistrements de migration pour TOUTES les applications, assurez-vous donc d'exécuter les deux autres lignes pour toutes les applications ou de les supprimer de manière sélective).

L' convert_to_southappel à la fin effectue une nouvelle migration et la falsifie (puisque votre base de données a déjà les tables correspondantes). Il n'est pas nécessaire de supprimer toutes les tables d'application pendant le processus.

Voici ce que je fais sur mon serveur de développement dev + production lorsque je dois me débarrasser de toutes ces migrations de développement inutiles:

  1. Assurez-vous que nous avons le même schéma de base de données des deux côtés
  2. supprimer tous les dossiers de migrations des deux côtés
  3. run ./manage.py réinitialiser le sud (comme le dit l'article) des deux côtés = efface la table sud *
  4. exécuter ./manage.py convert_to_south des deux côtés (simulation de migration 0001)
  5. puis je peux redémarrer pour faire des migrations et pousser les dossiers de migrations sur mon serveur

* sauf si vous ne souhaitez nettoyer qu'une seule application parmi d'autres, si c'est le cas, vous devrez modifier votre table south_history et supprimer uniquement les entrées concernant votre application.

Dominique Guardiola
la source
2
Pour mémoire, la réponse de l'auteur du Sud a été la suivante: tant que vous prenez soin de le faire sur tous les déploiements simultanément, cela ne devrait pas poser de problème. Personnellement, je ferais: rm -r appname / migrations / ./manage.py reset south ./manage.py convert_to_south appname (Notez que la partie "reset south" efface les enregistrements de migration pour TOUTES les applications, alors assurez-vous que vous exécutez les deux autres lignes pour toutes les applications ou supprimer sélectivement).
Adriaan Tijsseling
2
Notez également que si vous supprimez les tables, vous avez besoin à la manage.py schemamigration app name --initialplace de convert_to_south.
Adriaan Tijsseling
7
Depuis Django 1.5, la commande de gestion "reset" a disparu. Au lieu de cela, vous voudrez faire quelque chose à peu près comme south.models.MigrationHistory.objects.all().delete().
Andrew B.
13
@Dominique: Votre conseil concernant manage.py reset southest dangereux et peut détruire la base de données s'il y a des applications tierces utilisant south dans le projet, comme indiqué par @thnee ci-dessous. Étant donné que votre réponse a tellement de votes positifs, j'apprécierais vraiment que vous puissiez la modifier et ajouter au moins un avertissement à ce sujet, ou (encore mieux) la changer pour refléter l'approche @hobs (ce qui est tout aussi pratique, mais ne le fait pas affectent d'autres applications) - merci!
chrisv
3
Pourquoi était-ce si fortement voté? Vous ne devriez presque JAMAIS supprimer complètement votre table south_migrationhistory. Cela gâcherait complètement toutes les applications dépendantes avec des migrations que vous ne voulez pas toucher. La réponse de Hob est la bonne.
Cerin
188

Si vous avez besoin de réinitialiser de manière sélective (pour une seule application) les migrations qui prennent trop de temps, cela a fonctionné pour moi.

rm <app-dir>/migrations/*
python manage.py schemamigration <app-name> --initial
python manage.py migrate <app-name> 0001 --fake  --delete-ghost-migrations

N'oubliez pas de restaurer manuellement toutes les dépendances sur d'autres applications en ajoutant des lignes similaires depends_on = (("<other_app_name>", "0001_initial"),("<yet_another_app_name>", "0001_initial"))à votre <app-dir>/migrations/0001_initial.pyfichier, comme premier attribut de votre classe de migration juste en dessous class Migration(SchemaMigration):.

Vous pouvez alors ./manage.py migrate <app-name> --fake --delete-ghost-migrationssur d'autres environnements, par cette réponse SO . Bien sûr, si vous simulez la suppression ou la fausse, migrate zerovous devrez supprimer manuellement toutes les tables de base de données restantes avec une migration comme celle-ci .

Une option plus nucléaire consiste à ./manage.py migrate --fake --delete-ghost-migrationsutiliser le serveur de déploiement en direct suivi d'un [my] sqldump. Puis dirigez ce vidage dans [mon] sql sur les environnements où vous avez besoin de la base de données migrée et entièrement remplie. Sacrilège du sud, je sais, mais a travaillé pour moi.

plaques de cuisson
la source
2
Ce que je veux vraiment, c'est "prendre models.py comme un évangile, et me faire nettoyer à partir de là". Conserver ainsi la possibilité de configurer un déploiement à partir de zéro ou de travailler à partir d'un déploiement existant.
Bryce le
1
C'est ce que cela fait.
plaques de cuisson
2
@hobs J'étais en train de DependsOnUnknownMigrationsimuler la nouvelle migration initiale. Grâce à votre commentaire, je pourrais comprendre que je devrais mettre à jour la depends_ondéclaration partout où elle se réfère à cette application. C'est vraiment la meilleure réponse ici. Merci! :)
manu
55

Grâce aux réponses de Dominique Guardiola et aux plaques de cuisson, cela m'a aidé à résoudre un problème difficile. Cependant, il y a quelques problèmes avec la solution, voici mon point de vue.

L'utilisation manage.py reset southn'est pas une bonne idée si vous avez des applications tierces qui utilisent South, par exemple django-cms(essentiellement tout utilise South).

reset south supprimera tout l'historique de migration pour toutes les applications que vous avez installées.

Considérez maintenant que vous mettez à niveau vers la dernière version de django-cms, elle contiendra de nouvelles migrations comme 0009_do_something.py. Le sud sera sûrement confus lorsque vous essayez d'exécuter cette migration sans avoir 0001traversé 0008l'histoire de la migration.

Il est préférable / plus sûr de réinitialiser de manière sélective uniquement les applications que vous maintenez .


Tout d'abord, assurez-vous que vos applications n'ont pas de désynchronisation entre les migrations sur le disque et les migrations qui ont été exécutées sur la base de données. Sinon, il y aura mal à la tête.

1. Supprimer l'historique de migration de mes applications

sql> delete from south_migrationhistory where app_name = 'my_app';

2. Supprimer les migrations pour mes applications

$ rm -rf my_app/migrations/

3. Créer de nouvelles migrations initiales pour mes applications

$ ./manage.py schemamigration --initial my_app

4. Faux exécuter les migrations initiales pour mes applications

Cela insère les migrations south_migrationhistorysans toucher aux tables réelles:

$ ./manage.py migrate --fake my_app

Les étapes 3 et 4 ne sont en fait qu'une variante plus longue de manage.py convert_to_south my_app, mais je préfère ce contrôle supplémentaire, dans une situation aussi délicate que la modification de la base de données de production.

thnee
la source
2
J'ai édité ma réponse pour incorporer des correctifs pour les problèmes que vous avez trouvés (il suffit de les deviner en fonction de votre réponse) et je l'ai testée sur une base de données de production avec des millions de lignes.
plaques de cuisson
2
C'est à peu près ce que nous faisons. Si vous utilisez l'option --delete-ghost-migrations à l'étape 4, vous pouvez
omettre l'
Vous devez spécifier les noms d'applications explicitement dans ./manage.py migrate --fakesi vous ne souhaitez pas simuler la migration d'autres applications qui ont des migrations en attente.
wadim
2
@wadim D'où l'étape 0: «assurez-vous que vous n'avez pas de désynchronisation entre les migrations sur disque et les migrations qui ont été exécutées sur la base de données».
thnee
@thnee C'est vrai. Cela vaut probablement la peine de mentionner que vous faites référence à toutes les applications installées à l'étape 0. Connaissez-vous un moyen simple d'effectuer l'étape 0?
wadim
7

Comme Thnee (voir sa réponse), nous utilisons une approche plus douce de la suggestion de l'auteur du sud (Andrew Godwin) citée ailleurs ici, et nous séparons ce que nous faisons avec la base de code de ce que nous faisons à la base de données, pendant le déploiement , car nous avons besoin que les déploiements soient répétables:

Ce que nous faisons dans le code:

# Remove all the migrations from the app
$ rm -fR appname/migrations
# Make the first migration (don't touch the database)
$ ./manage.py schemamigration appname --initial

Ce que nous faisons à la base de données une fois que ce code est déployé

# Fake the migration history, wiping out the rest
$ ./manage.py migrate appname --fake --delete-ghost-migrations
tobych
la source
Je pense que j'ai juste fait la même chose, mais en supprimant manuellement les entrées de la base de données, plutôt que d'utiliser --delete_ghoist-migrations. Votre chemin est un peu plus agréable.
wobbily_col
1

Si vous travaillez uniquement sur la machine de développement, j'ai écrit une commande de gestion qui fait à peu près ce que Dominique a suggéré.

http://balzerg.blogspot.co.il/2012/09/django-app-reset-with-south.html

Contrairement à la suggestion de l'auteur sud, cela ne nuira PAS aux autres applications installées utilisant sud.

Idanzalz
la source
Et si, contrairement à l'auteur, vous souhaitez conserver les migrations existantes (c'est-à-dire que vous souhaitez réinitialiser l'application ainsi que l'historique de migration, mais conserver les migrations réelles), alors vous pouvez essayer ceci: goo.gl/0ZnWm
mgalgs
1

Ce qui suit n'est que si vous souhaitez réinitialiser toutes les applications. Veuillez sauvegarder toutes vos bases de données avant ce travail. Notez également votre depend_on dans les fichiers initiaux s'il y en a.

Pour une fois:

(1) find . -type d -name migrations -exec git rm -rf '{}' \;
(2) find . -type d -name migrations -exec rm -rf '{}' \;
(3) ./manage.py schemamigration <APP_NAME> --initial
(4) [GIT COMMIT]

Testez le bootstrap de votre projet avant de pousser. Ensuite, pour chaque machine locale / distante, appliquez ce qui suit:

(5) [GIT PULL]
(6) ./manage.py reset south
(7) ./manage.py migrate --fake

Faites les initiales (3) pour chaque application que vous souhaitez réimpliquer. Notez que reset (6) supprimera uniquement l'historique de migration, donc pas nuisible pour les bibliothèques. Les fausses migrations (7) remettront l'historique de migration de toutes les applications tierces installées.

yasc
la source
0

supprimer le fichier nécessaire du dossier de l'application

chemin de l'instance

 cd /usr/local/lib/python2.7/dist-packages/wiki/south_migrations

wiki -est mon application

Andrei Eremchuk
la source