Dans Django, existe-t-il un moyen simple de vérifier si toutes les migrations de bases de données ont été effectuées? J'ai trouvé manage.py migrate --list
, ce qui me donne les informations que je veux, mais le format n'est pas très lisible par machine.
Pour le contexte: j'ai un script qui ne devrait pas être lancé tant que la base de données n'a pas été migrée. Pour diverses raisons, il serait difficile d'envoyer un signal à partir du processus qui exécute les migrations. J'aimerais donc que mon script vérifie périodiquement la base de données pour voir si toutes les migrations ont été effectuées.
Coquille
La seule solution simple que j'ai trouvée jusqu'à présent est de courir
./manage.py showmigrations | grep '\[ \]'
qui générera une chaîne vide si toutes les migrations ont été appliquées.
Cependant, il est étroitement lié au format de sortie.
Python
J'ai vérifié le code source de migrate
command et il semble que cela devrait faire l'affaire:
from Django.db.migrations.executor import MigrationExecutor
from Django.db import connections, DEFAULT_DB_ALIAS
def is_database_synchronized(database):
connection = connections[database]
connection.prepare_database()
executor = MigrationExecutor(connection)
targets = executor.loader.graph.leaf_nodes()
return False if executor.migration_plan(targets) else True
# Usage example.
if is_database_synchronized(DEFAULT_DB_ALIAS):
# All migrations have been applied.
pass
else:
# Unapplied migrations found.
pass
1.10 notes de publication:
La nouvelle option
makemigrations --check
rend la commande quitter avec un statut différent de zéro lorsque des modifications de modèle sans migration sont détectées.
Essayer,
python manage.py migrate --list | grep "\[ \]\|^[a-z]" | grep "[ ]" -B 1
résultats,
<app_1>
[ ] 0001_initial
[ ] 0002_auto_01201244
[ ] 0003_auto_12334333
<app_2>
[ ] 0031_auto_12344544
[ ] 0032_auto_45456767
[ ] 0033_auto_23346566
<app_3>
[ ] 0008_auto_3446677
Mettre à jour :
Si vous avez mis à jour la version de Django> = 1.11
, utilisez la commande ci-dessous,
python manage.py showmigrations | grep '\[ \]\|^[a-z]' | grep '[ ]' -B 1
./manage.py showmigrations
#check quelles migrations déjà effectuées ont été appliquées ou non
(ou: ./manage.py showmigrations someApp
# pour une application spécifique seulement)
./manage.py makemigrations --dry-run
#check pour les migrations à effectuer
(ou: ./manage.py makemigrations someApp --dry-run
# pour une application spécifique seulement)
./manage.py makemigrations
# faire les migrations
(ou: ./manage.py makemigrations someApp
# pour une application spécifique seulement)
./manage.py showmigrations
#check quelles migrations déjà effectuées ont été appliquées ou non
(ou: ./manage.py showmigrations someApp
# pour une application spécifique seulement)
./manage.py sqlmigrate someApp 0001
#view modifications SQL pour une application et une migration spécifiques
./manage.py migrate
#apply migrations
(ou: ./manage.py migrate someApp
# pour une application spécifique seulement)
./manage.py showmigrations
#check quelles migrations déjà effectuées ont été appliquées ou non
(ou: ./manage.py showmigrations someApp
# pour une application spécifique seulement)
./manage.py makemigrations --dry-run
#check pour les migrations à effectuer
(ou: ./manage.py makemigrations someApp --dry-run
# pour une application spécifique seulement)
PS:./manage.py migrate someApp zero
#appliquer toutes les migrations pour une application spécifique
En utilisant le code @Ernest, j'ai écrit un manage_custom.py
pour les migrations en attente. Vous pouvez obtenir la liste des migrations en attente _ ainsi que {migrer ces migrations en attente (uniquement), vous faisant ainsi gagner du temps.
manage_custom.py
__author__ = "Parag Tyagi"
# set environment
import os
import sys
import Django
sys.path.append('../')
os.environ.setdefault('Django_SETTINGS_MODULE', 'settings')
Django.setup()
from Django.core.management import execute_from_command_line
from Django.db import DEFAULT_DB_ALIAS, connections
from Django.db.migrations.executor import MigrationExecutor
class Migration(object):
"""
A custom manage.py file for managing pending migrations (only)
"""
def __init__(self, migrate_per_migration_id=False):
"""
:param migrate_per_migration_id: Setting this to `True` will migrate each pending migration of any
particular app individually. `False` will migrate the whole app at a time.
You can add more arguments (viz. showmigrations, migrate) by defining the argument with prefix as 'ARGV_'
and create its functionality accordingly.
"""
self.ARG_PREFIX = 'ARGV_'
self.MIGRATE_PER_MIGRATION_ID = migrate_per_migration_id
self.ARGV_showmigrations = False
self.ARGV_migrate = False
@staticmethod
def get_pending_migrations(database):
"""
:param database: Database alias
:return: List of pending migrations
"""
connection = connections[database]
connection.prepare_database()
executor = MigrationExecutor(connection)
targets = executor.loader.graph.leaf_nodes()
return executor.migration_plan(targets)
def check_arguments(self, args):
"""
Method for checking arguments passed while running the command
:param args: Dictionary of arguments passed while running the script file
:return: Set the argument variable ('ARGV_<argument>') to True if found else terminate the script
"""
required_args = filter(None, [var.split(self.ARG_PREFIX)[1] if var.startswith(self.ARG_PREFIX)
else None for var in self.__dict__.keys()])
if any(k in args for k in required_args):
for arg in required_args:
if arg in args:
setattr(self, '{}{}'.format(self.ARG_PREFIX, arg), True)
break
else:
print ("Please pass argument: {}"
"\ne.g. python manage_custom.py {}".format(required_args, required_args[0]))
sys.exit()
def do_migration(self):
"""
Migrates all the pending migrations (if any)
"""
pending_migrations = self.get_pending_migrations(DEFAULT_DB_ALIAS)
if pending_migrations:
done_app = []
for mig in pending_migrations:
app, migration_id = str(mig[0]).split('.')
commands = ['manage.py', 'migrate'] + ([app, migration_id] if self.MIGRATE_PER_MIGRATION_ID else [app])
if self.ARGV_migrate and (app not in done_app or self.MIGRATE_PER_MIGRATION_ID):
execute_from_command_line(commands)
done_app.append(app)
Elif self.ARGV_showmigrations:
print (str(mig[0]))
else:
print ("No pending migrations")
if __== '__main__':
args = sys.argv
migration = Migration()
migration.check_arguments(args)
migration.do_migration()
Utilisation:
# below command will show all pending migrations
python manage_custom.py showmigrations
# below command will migrate all pending migrations
python manage_custom.py migrate
PS: Veuillez configurer l'environnement selon la structure de votre projet.
je vérifie en consultant la base de données à la table Django_migrations
qui stocke toutes les migrations appliquées
Voici ma solution Python pour obtenir des informations sur les états de migration:
from io import StringIO # for Python 2 use from StringIO import StringIO
from Django.core.management import call_command
def get_migration_state():
result = []
out = StringIO()
call_command('showmigrations', format="plan", stdout=out)
out.seek(0)
for line in out.readlines():
status, name = line.rsplit(' ', 1)
result.append((status.strip() == '[X]', name.strip()))
return result
Le résultat de cette fonction ressemble à ça:
[(True, 'contenttypes.0001_initial'),
(True, 'auth.0001_initial'),
(False, 'admin.0001_initial'),
(False, 'admin.0002_logentry_remove_auto_add')]
Peut-être que ça aide certains d'entre vous ..