Comment simplifier les migrations dans Django 1.7?

92

Il y a déjà des questions similaires pour South, mais j'ai commencé mon projet avec Django 1.7 et je n'utilise pas South.

Au cours du développement, de nombreuses migrations ont été créées, cependant le logiciel n'est pas encore livré et il n'existe aucune base de données à migrer. Par conséquent, je voudrais réinitialiser les migrations comme si mon modèle actuel était celui d'origine et recréer toutes les bases de données.

Quelle est la manière recommandée de faire cela?

EDIT: Depuis Django 1.8, il existe une nouvelle commande nommée squashmigrations qui résout plus ou moins le problème décrit ici.

Kit Fisto
la source
Que signifie réinitialiser une migration? Défaire?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

137

J'ai ça. Je viens de comprendre cela et c'est bien.

  • Tout d'abord, pour effacer le tableau des migrations:

    ./manage.py migrate --fake <app-name> zero
  • Supprimer le app-name/migrations/dossier ou le contenu.

  • Effectuez les migrations:

    ./manage.py makemigrations <app-name>
  • Enfin, rangez vos migrations sans apporter d'autres modifications à la base de données:

    ./manage.py migrate --fake <app-name>
kzorro
la source
5
C'est une bonne réponse. La simple suppression des migrations n'annule pas les dommages causés par les migrations défectueuses. Cela nettoie réellement l'ardoise et vous permet de recommencer.
rogueleaderr
15
Si vous développez un peu, cela devrait être la réponse acceptée.
tani-rokk
8
Bonne réponse en une ligne, frère, je n'ai aucune idée de ce que cela fait
bischoffingston
13
Cette ligne inverse simplement les migrations une par une, jusqu'à ce que zero. Pour le système de migrations Django, <app-name> est maintenant une nouvelle application et makemigrations <app-name>commencera à partir de 0001. --fakeempêche les tables d'être réellement modifiées, les migrations ne doivent être marquées que comme inversées et ne pas être réellement appliquées au schéma. (Ajout de petites explications par souci d'exhaustivité, @ tani-rokk, @Fabrizio)
Mir Nazim
17
manage.py migrate --fake <app-name> zeropour effacer le tableau des migrations, puis supprimez <app-name> / migrations / dossier ou son contenu. Puis manage.py makemigrations <app-name>et enfin faire manage.py migrate --fake <app-name>. Cela nettoiera vos migrations sans apporter d'autres modifications à la base de données.
doeke
36

Dans la version Django 1.7 des migrations, la fonctionnalité de réinitialisation qui était auparavant dans le sud a été abandonnée au profit de nouvelles fonctionnalités pour «écraser» vos migrations. C'est censé être un bon moyen de contrôler le nombre de migrations.

https://docs.djangoproject.com/en/dev/topics/migrations/#squashing-migrations

Si vous voulez toujours repartir de zéro, je suppose que vous pouvez toujours le faire en vidant la table des migrations et en supprimant les migrations après quoi vous exécuteriez à makemigrationsnouveau.

tijs
la source
2
Comment "supprimer les migrations" en plus de vider la table des migrations? Est-ce que je supprimerais tout le dossier ou uniquement les fichiers 00X _ *. Py?
Kit Fisto
avec South, vous pouvez supprimer le dossier migrations qui serait recréé lorsque vous exécutez à nouveau makemigrations. Je suppose que cela fonctionne de la même manière pour Django 1.7
tijs
4
Juste une note. dans Django 1.7, si vous supprimez sans précaution le dossier de migration, cela peut soulever une exception si votre modèle est un enfant d'un autreraise KeyError("Migration %s dependencies reference nonexistent parent node %r" % (migration, parent))
Algorithmatique
Plus précisément ./manage.py squashmigrations myapp 0004, toutes les migrations seront écrasées avant la migration 0004dans votre application myapp. Cela créera une seule migration écrasée.
Bryce Guinta
22

J'ai juste eu le même problème. Voici ma solution de contournement.

#!/bin/sh
echo "Starting ..."

echo ">> Deleting old migrations"
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc"  -delete


# Optional
echo ">> Deleting database"
find . -name "db.sqlite3" -delete

echo ">> Running manage.py makemigrations"
python manage.py makemigrations

echo ">> Running manage.py migrate"
python manage.py migrate

echo ">> Done"

La findcommande: http://unixhelp.ed.ac.uk/CGI/man-cgi?find

Abdelhamid Belarbi
la source
13
cela supprime les données, pas seulement les migrations
tables de cuisson
2
vous devez également supprimer les fichiers .pyc
shalbafzadeh
7

En supposant qu'il s'agit de la structure de votre projet,

project_root/
    app1/
        migrations/
    app2/
        migrations/
    ...
    manage.py
    remove_migrations.py

vous pouvez exécuter le script remove_migrations.py à partir de l'emplacement indiqué ci-dessus pour supprimer tous les fichiers de migration.

#remove_migrations.py
"""
Run this file from a Django =1.7 project root. 
Removes all migration files from all apps in a project.
""" 
from unipath import Path

this_file = Path(__file__).absolute()
current_dir = this_file.parent
dir_list = current_dir.listdir()

for paths in dir_list:
    migration_folder = paths.child('migrations')
    if migration_folder.exists():
        list_files = migration_folder.listdir()
        for files in list_files:
            split = files.components()
            if split[-1] != Path('__init__.py'):
                files.remove()

La suppression manuelle peut être fatigante si vous avez un projet élaboré. Cela m'a fait gagner beaucoup de temps. La suppression des fichiers de migration est sûre. Je l'ai fait un énième nombre de fois sans rencontrer de problèmes ... pour le moment.

Cependant, lorsque j'ai supprimé le dossier des migrations makemigrationsou migrateque je n'ai pas recréé le dossier pour moi. Le script s'assure que le dossier de migration avec ses __init__.pyrestes en place, ne supprimant que les fichiers de migration.


la source
vous pouvez simplement supprimer les dossiers de migrations et les recréer avec un init .py vide (par exemple touch migrations/__init__.py)
hobs
6
  1. Supprimer les fichiers: delete_migrations.py (à la racine de prj):
import os

for root, dirs, files in os.walk(".", topdown=False):
  for name in files:
      if '/migrations' in root and name != '__init__.py':
          os.remove(os.path.join(root, name))
  1. DELETE FROM django_migrations Where app in ('app1', 'app2');

  2. ./manage.py makemigrations

  3. ./manage.py migrer --fake

OU, vous pouvez écrire la migration à partir de tout cela

Ibrohim Ermatov
la source
J'ai dû spécifier les noms des applications pour ./manage.py makemigrationstravailler, comme ceci:./manage.py makemigrations orders alerts
Salami
4

J'essaye différentes commandes et certaines des réponses m'aident. Seule cette séquence dans mon cas a corrigé les deux dépendances brisées dans les migrations dans MYAPP et nettoyer toutes les migrations passées à partir de zéro.

Avant de faire cela, assurez-vous que la base de données est déjà synchronisée (par exemple, n'ajoutez pas de nouveau champ Modèle ici ou ne modifiez pas les options Meta).

rm -Rf MYAPP/migrations/*
python manage.py makemigrations --empty MYAPP
python manage.py makemigrations
python manage.py migrate --fake MYAPP 0002

Où 0002 est le numéro de migration renvoyé par la dernière commande makemigrations.

Vous pouvez maintenant réexécuter makemigrations / migrate normalement car la migration 0002 est stockée mais pas reflétée dans la base de données déjà synchronisée.

chirale
la source
Parmi toutes les solutions mentionnées ci-dessus, seule cela a fonctionné pour moi sans problème et sans supprimer la base de données.
Vivek Jha
3

Si vous ne vous souciez pas des migrations précédentes, qu'en est-il de la suppression de toutes les migrations dans le répertoire migrations /? vous commencerez la séquence de migration à partir de zéro, en prenant votre modèle actuel comme référence comme si vous aviez écrit le modèle entier maintenant.

Si vous ne me faites pas suffisamment confiance pour les supprimer, essayez de les éloigner à la place.

vokimon
la source
Quelle est l'importance de conserver les anciennes migrations? Mes questions se posent lorsque l'on essaie de passer de django 1.6 à 1.8.
Jay Modi
Les migrations sont simplement un historique des modifications que vous avez apportées à la base de données. J'ai suivi les conseils de vokiman plus d'une fois lorsque ma chaîne de migration cesse de fonctionner.
Adam Starrh le
1

Un moyen simple est

Accédez à chaque application et supprimez les fichiers de migration.

Accédez ensuite à la table django-migrtaions dans la base de données et tronquez-la (supprimez toutes les entrées).

Après cela, vous pouvez à nouveau créer des migrations.

sprksh
la source
1
lors de la suppression des fichiers de migration, assurez-vous de ne pas supprimer les fichiers init .
sprksh le
Cela m'a vraiment aidé. J'ai supprimé toutes les migrations, supprimé les tables de ma base de données sqlite, mais j'étais toujours incapable de faire des migrations ... cependant, une fois que j'ai restauré les fichiers _init_ .py (doh), j'ai pu recommencer les migrations et reprendre la croisière. @sprksh = Gareautrain!
twknab
0

cd vers le répertoire src cd /path/to/src

supprimer les répertoires de migration rm -rf your_app/migrations/

notez que cela doit être fait pour chaque application séparément

émigrer python3.3 manage.py migrate

si vous souhaitez recommencer python3.3 manage.py makemigrations your_app

Canard en caoutchouc
la source
0

Si vous êtes en mode développement et que vous souhaitez simplement tout réinitialiser (base de données, migrations, etc.), j'utilise ce script basé sur la réponse d'Abdelhamid Ba. Cela effacera les tables de la base de données (Postgres), supprimera tous les fichiers de migration, réexécutera les migrations et chargera mes montages initiaux:

#!/usr/bin/env bash
echo "This will wipe out the database, delete migration files, make and apply migrations and load the intial fixtures."

while true; do
    read -p "Do you wish to continue?" yn
    case $yn in
        [Yy]* ) make install; break;;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
    esac
done

echo ">> Deleting old migrations"
find ../../src -path "*/migrations/*.py" -not -name "__init__.py" -delete

# Optional
echo ">> Deleting database"
psql -U db_user -d db_name -a -f ./reset-db.sql

echo ">> Running manage.py makemigrations and migrate"
./migrations.sh

echo ">> Loading initial fixtures"
./load_initial_fixtures.sh

echo ">> Done"

Fichier reset-db.sql:

DO $$ DECLARE
    r RECORD;
BEGIN
    -- if the schema you operate on is not "current", you will want to
    -- replace current_schema() in query with 'schematodeletetablesfrom'
    -- *and* update the generate 'DROP...' accordingly.
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
        EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
    END LOOP;
END $$;

fichier migration.sh:

#!/usr/bin/env bash
cd ../../src
./manage.py makemigrations
./manage.py migrate

Fichier load_initial_fixtures.sh:

#!/usr/bin/env bash
cd ../../src
./manage.py loaddata ~/path-to-fixture/fixture.json

Assurez-vous simplement de modifier les chemins pour qu'ils correspondent à votre application. J'ai personnellement ces scripts dans un dossier appelé project_root / script / local, et les sources de django sont dans project_root / src.

mrmuggles
la source
0

Après avoir supprimé chaque dossier «migrations» dans mon application (manuellement), j'ai exécuté:

./manage.py dbshell
delete from django_migrations;

Ensuite, j'ai pensé que je pouvais faire ./manage.py makemigrationspour les régénérer tous. Cependant, aucun changement n'a été détecté. J'ai ensuite essayé de spécifier une application à la fois: ./manage.py makemigrations foo, ./manage.py makemigrations bar. Cependant, cela a abouti à des dépendances circulaires qui n'ont pas pu être résolues.

Enfin, j'ai exécuté une seule commande makemigrations qui spécifiait TOUTES mes applications (sans ordre particulier):

./manage.py makemigrations foo bar bike orange banana etc

Cette fois, cela a fonctionné - les dépendances circulaires ont été automatiquement résolues (cela a créé des fichiers de migration supplémentaires si nécessaire).

Ensuite, j'ai pu courir ./manage.py migrate --fakeet j'ai repris mon activité.

shacker
la source