无法使用继承的Django模型的Meta类配置在继承的抽象模型中定义的字段

7 投票
3 回答
6230 浏览
提问于 2025-04-15 14:00

我想用一个继承模型的Meta类里的属性,来配置一个在更高层次的抽象模型中定义的字段:

class NamedModel(models.Model):
    class Meta:
        abstract = True
        verbose_name = 'object'

    name = models.CharField("Name",
        max_length=200,
        db_index=True,
        help_text="A meaningful name for this %s." % Meta.verbose_name)
        # see what I'm trying to do here?
    )
    ...

class OwnedModel(NamedModel):
    class Meta(NamedModel.Meta):
        verbose_name = 'owned object'

我希望OwnedModel表单中的名称字段的帮助文本显示为“这个拥有对象的有意义名称”。但实际上并不是这样:缺少了“owned”这个词,这表明在设置模型时使用的是NamedModel.Meta中的verbose_name,而不是OwnedModel.Meta中的。

从继承的角度来看,这和我预期的有些不符:有没有办法让这个字段的创建方式是Meta.verbose_name引用非抽象模型类中的值,而不是定义字段的抽象模型中的值呢?

还是说我想得太简单了?

(这看起来可能是个微不足道的例子,确实是:但我只是想用这个例子来说明我正在尝试做的一个更重要和复杂的事情)

非常感谢!

3 个回答

1

其实我最后做了以下这些事情。基础模型添加了一个叫做 dynamic_field_definition() 的类方法,这个方法可以用来修补字段,其中的 cls 参数是正确的(继承的)类。这意味着这个 cls 的 Meta 属性是那个正确的子类,而不是原来的基础类。

然后我把这个方法连接到 class_prepared 信号上,这样你就知道其他一切都准备好了。

class NamedModel(models.Model):
    ...
    @classmethod
    def dynamic_field_definition(cls):
        pass

def dynamic_field_definition(sender, **kwargs):
    if issubclass(sender, NamedModel):
        sender.dynamic_field_definition()
class_prepared.connect(dynamic_field_definition)

接着,随着模型类变化的字段属性就可以通过这个类方法重新配置(或者更可能是在派生类中重写的方法)。

这是一种稍微有点小技巧的方式,可以给 Django 模型带来最后一点面向对象的特性,但对我来说效果很好。

2

你为什么不试着创建一个类呢?

class BaseNamedModelMeta:
    abstract = True
    verbose_name = "your text"

然后你可以像这样继承并重写你想要的内容:

class OwnedModel(NamedModel):
    class Meta(BaseNamedModelMeta):
        verbose_name = 'owned object'
1

我觉得这个问题出现的原因是因为使用了Meta.verbose_name,而NamedModel.name是在解析NamedModel类的时候创建的。所以当OwnedModel类被解析时,就没有机会去更改任何东西了。

也许你可以在之后给OwnedModel.name设置help_text属性,但这可能也会影响到NamedModel.name。

在类似的情况下,我通常会把可变的部分放在模型的类属性里(不是Meta),然后在运行时使用方法或属性来生成我需要的文本。

撰写回答