使用元类设置时 Django 迁移忽略 db_table

Posted

技术标签:

【中文标题】使用元类设置时 Django 迁移忽略 db_table【英文标题】:Django migrations ignoring db_table when set using metaclass 【发布时间】:2018-12-09 10:42:58 【问题描述】:

我正在使用元类自动将我的 Django 模型数据库表名从驼峰式大小写设置为“_”分隔名称,例如MyGreatModel 将有一个类似appname_my_great_model 的表名,而不是默认的appname_mygreatmodel

class PrettyModelBase(ModelBase):

    def __new__(cls, name, bases, attrs):
        super_new = ModelBase.__new__(cls, name, bases, attrs)
        module_name = camel_to_underscore(name)
        model_module = sys.modules[cls.__module__]

        app_label = super_new.__module__.split('.')[-2]
        db_table = '%s_%s' % (app_label, module_name)
        if not getattr(super_new._meta, 'proxy', False):
             super_new._meta.db_table = db_table

        return super_new


class BaseModel(models.Model):

    __metaclass__ = PrettyModelBase

    class Meta:
        abstract = True

class MyGreatModel(BaseModel):
    somefield = models.TextField(default="")

但是迁移似乎没有选择这个db_table 名称。如果我运行 makemigrations,则 CreateModel 不会在此模型的 options 中显示 db_table。如果我在MyGreatModelclass Meta 中对其进行硬编码,则可以。此外,如果我检查要使用 python manage.py sqlmigrate... 运行的 SQL,那么它表明它将创建 appname_mygreatmodel 表,而不是分隔表名。

但是,如果我确实运行此迁移,然后在 Django shell 中检查模型,那么MyGreatModel._meta.db_table 会显示my_great_model,正如我对元类所期望的那样。如果我手动将 db_table 属性添加到 CreateModel 的 0001 初始化迁移选项,那么后续迁移也一切正常,但我认为 Django 应该自动执行此操作...

为什么 Django 迁移没有在此处获取 db_table

我正在使用Django==1.10.5

感谢您的帮助

【问题讨论】:

我不确定为什么这不起作用,但我的建议是使用公共的Meta API,而不是使用_meta。具体来说,在调用ModelBase.__new__() 之前设置Meta.db_table(来自attrs)。这将大大减少您对 Django 元类和迁移实现的内部细节的依赖。 运气好了吗?我遇到了完全相同的问题。我试图通过将所有表名设置为“app_label.model_name”而不是“app_label_model_name”来利用 Postgres 模式。 我只是觉得这是个坏主意。为什么要更改表的名称?此外,Django 1.10.5 也不安全。您需要至少更新到 1.11,最好是 2.2。 【参考方案1】:

这个问题在 django-developers 邮件列表中再次提出:https://groups.google.com/forum/#!msg/django-developers/ncMCwMF2J3g/V3guuDbJCwAJ

Django 迁移使用model._meta.original_attrs 来确定元类的定义:https://github.com/django/django/blob/stable/2.2.x/django/db/migrations/state.py#L454

因此,如果您在创建后动态地改变model._meta,您还需要相应地改变它的original_attrs dict。我认为这应该有效(未经测试)。

【讨论】:

以上是关于使用元类设置时 Django 迁移忽略 db_table的主要内容,如果未能解决你的问题,请参考以下文章

makemigrations 忽略所有领域 (DJANGO)

如何忽略生产中的一些迁移

Django:调用元类库时出错

django项目中.gitignore文件忽略上传的文件,以及数据库迁移文件到底是否需要上传吗?

Django:在迁移运行时更改设置值

Django 忽略模型字段