Skip to main content
 首页 » 编程设计

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

2024年12月31日23zfyouxi

我正在使用元类自动将我的 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。如果我在 MyGreatModel 的 class Meta 中对其进行硬编码,那么它就会执行。此外,如果我检查要使用 python manage.py sqlmigrate... 运行的 SQL,则它表明它将创建 appname_mygreatmodel 表,而不是分隔的表名。

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

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

我正在使用 Django==1.10.5。

感谢您的帮助

请您参考如下方法:

这个问题在 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 字典。我认为这应该可行(未经测试)。