web-dev-qa-db-fra.com

Rechercher les migrations Django en attente

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.

21
Moss Collum

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
35
Ernest Ten

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.

11
minusf

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

4
Jan Kyu Peblik

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 

0

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

0
chsymann