Python 检查挂起的 Django 迁移

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31838882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 10:38:12  来源:igfitidea点击:

Check for pending Django migrations

pythondjangodjango-migrations

提问by Moss Collum

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, but the format isn't very machine readable.

在 Django 中,是否有一种简单的方法来检查是否所有数据库迁移都已运行?我发现manage.py migrate --list,它给了我我想要的信息,但格式不是很机器可读。

For context: I have a script that shouldn't start running until the database has been migrated. For various reasons, it would be tricky to send a signal from the process that's running the migrations. So I'd like to have my script periodically check the database to see if all the migrations have run.

对于上下文:我有一个脚本,在迁移数据库之前不应开始运行。由于各种原因,从运行迁移的进程发送信号会很棘手。所以我想让我的脚本定期检查数据库以查看是否所有迁移都已运行。

回答by Ernest Ten

Shell

贝壳

The only simple solution I've found so far is running

到目前为止我发现的唯一简单的解决方案是运行

./manage.py showmigrations | grep '\[ \]'

which will output an empty string in case all migrations have been applied.

如果已应用所有迁移,它将输出一个空字符串。

However, it is closely tied to the output format.

但是,它与输出格式密切相关。

Python

Python

I checked the source code of migratecommand and it seems like this should do the trick:

我检查了migrate命令的源代码,看起来这应该可以解决问题:

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 not executor.migration_plan(targets)

# Usage example.
if is_database_synchronized(DEFAULT_DB_ALIAS):
    # All migrations have been applied.
    pass
else:
    # Unapplied migrations found.
    pass

回答by Parag Tyagi -morpheus-

Using @Ernest code, I've written a manage_custom.pyfor pending migrations. You can get the list of pending migrationsalso migratethose pending migrations (only), hence saving your time.

使用@Ernest 代码,我manage_custom.py为挂起的迁移编写了一个。您可以获得挂起的迁移列表,也可以迁移那些挂起的迁移(仅限),从而节省您的时间。

manage_custom.py

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.

PS:请根据您的项目结构设置环境。

回答by Parag Tyagi -morpheus-

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,

如果您已更新 Django 版本 >= 1.11,请使用以下命令,

python manage.py showmigrations | grep '\[ \]\|^[a-z]' | grep '[  ]' -B 1

回答by minusf

1.10 release notes:

1.10 发行说明:

The new makemigrations --checkoption makes the command exit with a non-zero status when model changes without migrations are detected.

makemigrations --check当检测到没有迁移的模型更改时,新选项使命令以非零状态退出。

If you don't want to create the migrations, combine it with --dry-run:

如果您不想创建迁移,请将其与--dry-run

python manage.py makemigrations --check --dry-run

Note that this doesn't check whether the migrations were applied, it only checks whether the migration files were created.

请注意,这不会检查是否应用了迁移,它只会检查是否创建了迁移文件。

回答by Jan Kyu Peblik

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

./manage.py showmigrations#检查哪些已经进行的迁移已被应用
(或:./manage.py showmigrations someApp#仅针对特定应用程序)

./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 --dry-run#检查要进行的迁移
(或:./manage.py makemigrations someApp --dry-run#仅针对特定应用程序)

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

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

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

./manage.py showmigrations#检查哪些已经进行的迁移已被应用
(或:./manage.py showmigrations someApp#仅针对特定应用程序)

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

./manage.py sqlmigrate someApp 0001#查看特定应用程序和迁移的 SQL 更改

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

./manage.py migrate#apply 迁移
(或:./manage.py migrate someApp#仅针对特定应用程序)

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

./manage.py showmigrations#检查哪些已经进行的迁移已被应用
(或:./manage.py showmigrations someApp#仅针对特定应用程序)

./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 --dry-run#检查要进行的迁移
(或:./manage.py makemigrations someApp --dry-run#仅针对特定应用程序)

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

PS:
./manage.py migrate someApp zero#unapply 特定应用程序的所有迁移

回答by chsymann

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

这是我的 Python 解决方案,用于获取有关迁移状态的一些信息:

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

也许它对你们中的一些人有帮助..

回答by Ryabchenko Alexander

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

我通过查找django_migrations存储所有应用迁移的表来检查它。