首页 文章

如何覆盖django中超类模型字段的详细名称

提问于
浏览
27

假设我有一个继承自SuperFoo的模型Foo:

class SuperFoo(models.Model):
    name = models.CharField('name of SuperFoo instance', max_length=50)
    ...

class Foo(SuperFoo):
    ... # do something that changes verbose_name of name field of SuperFoo

在类Foo中,我想覆盖SuperFoo的name字段的verbose_name . 我可以吗?如果没有,是在模型表单定义中设置标签以使其显示在模板中的最佳选项吗?

4 回答

  • 51

    我用过的一个简单的黑客是:

    class SuperFoo(models.Model):
        name = models.CharField('name of SuperFoo instance', max_length=50)
        ...
        class Meta: 
            abstract = True
    
    class Foo(SuperFoo):
        ... # do something that changes verbose_name of name field of SuperFoo
    Foo._meta.get_field('name').verbose_name = 'Whatever'
    
  • 5

    请记住,修改Foo._meta.fields也会影响超类 - 因此只有在超类是抽象的时候才真正有用,我已经将@Gerry放弃的答案包装成可重复使用的类装饰器:

    def modify_fields(**kwargs):
        def wrap(cls):
            for field, prop_dict in kwargs.items():
                for prop, val in prop_dict.items():
                    setattr(cls._meta.get_field(field), prop, val)
            return cls
        return wrap
    

    像这样使用它:

    @modify_fields(timestamp={
        'verbose_name': 'Available From',
        'help_text': 'Earliest date you can book this'})
    class Purchase(BaseOrderItem):
        pass
    

    上面的示例更改了继承字段“timestamp”的verbose_name和help_text . 您可以传入与要修改的字段一样多的关键字参数 .

  • 10

    您最好的选择是在表单中设置/更改标签 . 参考 Foo 模型的 name 字段(例如,在 Foo._meta.fields 中查找)实际上会为您提供 SuperFooname 字段的引用,因此更改其 verbose_name 将在两个模型中更改它 .

    此外,将 name 字段添加到 Foo 类也不起作用,because ...

    在父模型中覆盖字段会导致诸如初始化新实例(指定在Model .__ init__中初始化哪个字段)和序列化等方面的困难 . 这些是普通Python类继承不必以完全相同的方式处理的特性,因此Django模型继承和Python类继承之间的区别不仅仅是任意的 .

  • 5

    看看Django-CMS如何做到这一点,它们覆盖了继承自 CMSPlugin 的模型中的 db_table 字段 . 基础知识(我也用于我自己的东西)归结为:

    class SuperFooMetaClass(ModelBase):
        def __new__(cls, name, bases, attrs):
            new_class = super(SuperFooMetaClass, cls).__new__(cls, name, bases, attrs)
            new_class._meta.verbose_name = "...."   # perhaps only if not customized
            return new_class
    
    
    class SuperFoo(models.Model):
        __metaclass__ = SuperFooMetaClass
    
        ....
    

    您可以添加一些检查,例如仅更新子类(不是直接类型),或仅在未自定义值时更新 .

相关问题