Check for pending Django migrations

前端 未结 8 2056
孤独总比滥情好
孤独总比滥情好 2021-02-01 13:05

In Django, is there an easy way to check whether all database migrations have been run? I\'ve found manage.py migrate --list, which gives me the information I want,

相关标签:
8条回答
  • 2021-02-01 13:18

    Using @Ernest code, I've written a manage_custom.py for pending migrations. You can get the list of pending migrations also migrate those pending migrations (only), hence saving your time.

    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 __name__ == '__main__':
        args = sys.argv
        migration = Migration()
        migration.check_arguments(args)
        migration.do_migration()
    

    Usage:

    # 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: Please setup environment as per your project structure.

    0 讨论(0)
  • 2021-02-01 13:21

    3.1 release notes

    The new migrate --check option makes the command exit with a non-zero status when unapplied migrations are detected.

    https://docs.djangoproject.com/en/3.1/ref/django-admin/#cmdoption-migrate-check

    so finally we can

    python manage.py migrate --check

    0 讨论(0)
  • 2021-02-01 13:25

    Try,

    python manage.py migrate --list | grep "\[ \]\|^[a-z]" | grep "[ ]" -B 1
    

    returns,

    <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
    


    Update:

    If you have updated Django version >= 1.11, use below command,

    python manage.py showmigrations | grep '\[ \]\|^[a-z]' | grep '[  ]' -B 1
    
    0 讨论(0)
  • 2021-02-01 13:26

    Here is my Python soloution to get some information about the migration-states:

    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
    

    The result of this function looks like that:

    [(True, 'contenttypes.0001_initial'),
     (True, 'auth.0001_initial'),
     (False, 'admin.0001_initial'),
     (False, 'admin.0002_logentry_remove_auto_add')]
    

    Maybe it helps some of you guys..

    0 讨论(0)
  • 2021-02-01 13:27

    ./manage.py showmigrations #check which already-made migrations have been applied or not
    (or: ./manage.py showmigrations someApp #for specific app alone)

    ./manage.py makemigrations --dry-run #check for migrations to be made
    (or: ./manage.py makemigrations someApp --dry-run #for specific app alone)

    ./manage.py makemigrations #make the migrations
    (or: ./manage.py makemigrations someApp #for specific app alone)

    ./manage.py showmigrations #check which already-made migrations have been applied or not
    (or: ./manage.py showmigrations someApp #for specific app alone)

    ./manage.py sqlmigrate someApp 0001 #view SQL changes for specific app & migration

    ./manage.py migrate #apply migrations
    (or: ./manage.py migrate someApp #for specific app alone)

    ./manage.py showmigrations #check which already-made migrations have been applied or not
    (or: ./manage.py showmigrations someApp #for specific app alone)

    ./manage.py makemigrations --dry-run #check for migrations to be made
    (or: ./manage.py makemigrations someApp --dry-run #for specific app alone)

    PS:
    ./manage.py migrate someApp zero #unapply all migrations for specific app

    0 讨论(0)
  • 2021-02-01 13:36

    I checked it by looking up the table django_migrations, which stores all applied migrations.

    0 讨论(0)
提交回复
热议问题