检测代码是不是在 migrate/makemigrations 命令的上下文中运行

Posted

技术标签:

【中文标题】检测代码是不是在 migrate/makemigrations 命令的上下文中运行【英文标题】:Detect whether code is being run in the context of migrate/makemigrations command检测代码是否在 migrate/makemigrations 命令的上下文中运行 【发布时间】:2016-01-13 15:31:59 【问题描述】:

我有一个带有动态选择的模型,如果我能保证代码在出现django-admin.py migrate / makemigrations 命令的情况下正在运行以防止它创建或警告无用的选择,我想返回一个空的选择列表变化。

代码:

from artist.models import Performance
from location.models import Location

def lazy_discover_foreign_id_choices():
    choices = []

    performances = Performance.objects.all()
    choices += performance.id: str(performance) for performance in performances.items()

    locations = Location.objects.all()
    choices += location.id: str(location) for location in locations.items()

    return choices
lazy_discover_foreign_id_choices = lazy(lazy_discover_foreign_id_choices, list)


class DiscoverEntry(Model):
    foreign_id = models.PositiveIntegerField('Foreign Reference', choices=lazy_discover_foreign_id_choices(), )

所以我想如果我可以在lazy_discover_foreign_id_choices 中检测到运行上下文,那么我可以选择输出一个空的选择列表。我正在考虑测试sys.argv__main__.__name__,但我希望可能有更可靠的方法或API?

【问题讨论】:

您的选择动态如何?你能发布一些代码吗? 当然,添加代码 如何导入PerformanceLocation 更新代码以显示导入。 对我来说还有另一个问题:这些不是这些模型的历史版本。这可能会导致迁移中出现意外行为,因为您导入的模型是最新版本,而在迁移中,您会获得当前的迁移版本。 【参考方案1】:

使用django.db.models.signals.pre_migrate 应该足以检测migrate 命令。缺点是不能在配置阶段使用。

【讨论】:

【参考方案2】:

这是一种相当简单的方法(因为 django 已经为我们创建了标志):

import sys
def lazy_discover_foreign_id_choices():
    if ('makemigrations' in sys.argv or 'migrate' in sys.argv):
        return []
    # Leave the rest as is.

这应该适用于所有情况。

【讨论】:

哦,这是一个非常好的方法。 哇,我也有同样的想法!这是一种非常简单但有效的方法。 有什么方法可以隔离测试的迁移阶段?【参考方案3】:

我能想到的一个解决方案是子类化 Django makemigrations 命令以在实际执行实际操作之前设置一个标志。

示例:

将该代码放入<someapp>/management/commands/makemigrations.py,它将覆盖Django 的默认makemigrations 命令。

from django.core.management.commands import makemigrations
from django.db import migrations


class Command(makemigrations.Command):
    def handle(self, *args, **kwargs):
        # Set the flag.
        migrations.MIGRATION_OPERATION_IN_PROGRESS = True

        # Execute the normal behaviour.
        super(Command, self).handle(*args, **kwargs)

migrate 命令执行相同操作。

并修改您的动态选择功能:

from django.db import migrations


def lazy_discover_foreign_id_choices():
    if getattr(migrations, 'MIGRATION_OPERATION_IN_PROGRESS', False):
        return []
    # Leave the rest as is.

它非常hacky,但设置起来相当容易。

【讨论】:

感谢您的建议,但这不起作用。似乎模型字段选择在Command.handle()之前执行 我在我的一个项目上试过,它似乎工作,我会调查。 @DanH 我确认它在全新安装的 Django 1.8.5 上运行良好,您确定它是执行的新命令而不是默认命令吗? 对不起,你是对的,它适用于makemigrations。然而,同样的概念似乎不适用于migrate 命令。 migrate 的问题在于,如果我在 migrate.Command.handle()lazy_discover_foreign_id_choices() 中都设置了异常,Command.handle() 执行得太晚了。不确定这是否是一个结论性的测试?

以上是关于检测代码是不是在 migrate/makemigrations 命令的上下文中运行的主要内容,如果未能解决你的问题,请参考以下文章

如何根据升级代码检测是不是安装了应用程序

JVM 是不是有能力检测并行化机会?

用于检测设备是不是水平的 iOS 代码

如何检测我的代码是不是应该模拟?

网页代码 JS代码 检测手机或是Pad设备 是不是安装某软件 之后做相应的跳转

检测是不是从在 3.5 上运行的 C# 代码安装了 MSBuild/.net 4?