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

时间:2009-05-29 19:30:57

标签: python django inheritance django-models

假设我有一个继承自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名称字段的verbose_name。我可以吗?如果没有,是在模型表单定义中设置标签以使其显示在模板中的最佳选择吗?

5 个答案:

答案 0 :(得分: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'

答案 1 :(得分:10)

请记住,修改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。您可以传入与要修改的字段一样多的关键字参数。

答案 2 :(得分:5)

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

此外,向name课程添加Foo字段也不起作用,because ...

  

覆盖父模型中的字段   导致诸如此类领域的困难   初始化新实例(指定   哪个领域正在进行中   Model.__init__)和序列化。   这些是普通Python的功能   类继承不必处理   以完全相同的方式,所以   Django模型之间的区别   继承和Python类   继承不仅仅是武断的。

答案 3 :(得分:5)

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

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

    ....

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

答案 4 :(得分:0)

我有不同的子类,它们是从同一基类派生的。而且我只关心Django Admin界面中的表单视图。

对我而言唯一有效的解决方案是自定义Django Admin界面并在此处设置verbose_name(或help_text):

class FooAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        form.base_fields['name'].verbose_name = "my verbose name"
        return form

admin.site.register(models.Foo, FooAdmin)