如果字段选项列表发生更改,请停止Django创建迁移

gue*_*tli 16 python django database-migration

我有一个名为"foocore"的django核心应用程序.

有几个可选的类似插件的应用程序.例如"superfoo".

在我的例子中,每个插件都在CharField模型中添加了一个新选项,该模型属于"foocore".

如果选择列表发生更改,Django迁移会检测更改.

我认为这不是必要的.至少有一位其他开发者认为相同:

https://code.djangoproject.com/ticket/22837

class ActivePlugin(models.Model):
    plugin_name = models.CharField(max_length=32, choices=get_active_plugins())
Run Code Online (Sandbox Code Playgroud)

获取选择的代码:

class get_active_plugins(object):
    def __iter__(self):
        for item in ....:
            yield item
Run Code Online (Sandbox Code Playgroud)

核心"foocore"在几个项目中使用,每个安装都有一组不同的插件.Django试图创建无用的迁移....

有办法解决这个问题吗?

Wol*_*lph 11

有关详细信息,请参阅此错误报告和讨论:https://code.djangoproject.com/ticket/22837

建议的解决方案是使用callable作为选择的参数,但看起来这并没有针对字段执行,而是仅针对表单执行.

如果你真的需要动态选择而不是ForeignKey最佳解决方案.

另一种解决方案可以是通过字段的自定义清理方法和/或创建自定义表单来添加需求.表单字段确实支持可调用choices.

有关详细信息,请参阅此答案:https://stackoverflow.com/a/33514551/54017

  • 在这种情况下,你可能会因为一个干净的解决方案而运气不好.我只能想到黑客为你的情况解决它...修改运行时的选择,如果`sys.argv`包含`makemigrations`等硬编码选项. (2认同)

Ari*_*iel 6

我有一个类似的问题。我的选择是动态的(从起点到现在的所有年份),每年第一次makemigrations运行它都会为新选择生成新的迁移。我找到的解决方案是自定义字段,这样choices更改就不会被检测到makemigrations

from django.db import models


class YearField(models.IntegerField):

    description = "A year from 2015 to the present"

    def deconstruct(self):
        name, path, args, kwargs = super(YearField, self).deconstruct()
        # Ignore choice changes when generating migrations
        kwargs.pop('choices', None)
        return (name, path, args, kwargs)
Run Code Online (Sandbox Code Playgroud)


Tom*_*ena 5

我有一个类似的问题,我为一个具有相同通用结构的Django 1.6项目制作的自定义字段.我找到了以下可行的解决方案:

class ActivePluginMeta(ModelBase):
    def __new__(cls, name, bases, attrs):
        # Override choices attr
        cls = models.base.ModelBase.__new__(cls, name, bases, attrs)
        setattr(cls._meta.get_field('plugin_name'), 'choices', cls.plugin_name_choices)
        return cls

class ActivePlugin(models.Model, metaclass=ActivePluginMeta):
    plugin_name_choices = get_active_plugins()
    plugin_name = models.CharField(max_length=32, choices=[])
Run Code Online (Sandbox Code Playgroud)

对于python 3,对于python 2,你必须指定元类,如下所示:

class ActivePlugin(models.Model):
    __metaclass__ = ActivePluginMeta

    plugin_name_choices = get_active_plugins()
    plugin_name = models.CharField(max_length=32, choices=[])
Run Code Online (Sandbox Code Playgroud)