how to override the verbose name of a superclass model field in django

后端 未结 5 1523
梦如初夏
梦如初夏 2020-12-05 02:35

Let\'s say that I have a model Foo that inherits from SuperFoo:

class SuperFoo(models.Model):
    name = models.CharField(\'name of SuperFoo instance\', max_         


        
相关标签:
5条回答
  • 2020-12-05 02:57

    A simple hack I have used is:

    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'
    
    0 讨论(0)
  • 2020-12-05 03:01

    Your best bet would be setting/changing the label in the form itself. Referring to the name field of the Foo model (eg. by looking it up in Foo._meta.fields) will actually give you a reference to the name field of SuperFoo, so changing its verbose_name will change it in both models.

    Also, adding a name field to the Foo class won't work either, because...

    Overriding fields in a parent model leads to difficulties in areas such as initialising new instances (specifying which field is being intialised in Model.__init__) and serialization. These are features which normal Python class inheritance doesn't have to deal with in quite the same way, so the difference between Django model inheritance and Python class inheritance isn't merely arbitrary.

    0 讨论(0)
  • 2020-12-05 03:05

    Bearing in mind the caveat that modifying Foo._meta.fields will affect the superclass too - and therefore is only really useful if the superclass is abstract, I've wrapped the answer @Gerry gave up as a reusable class decorator:

    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
    

    Use it like this:

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

    The example above changes the verbose_name and help_text for the inherited field 'timestamp'. You can pass in as many keyword args as there are fields you want to modify.

    0 讨论(0)
  • 2020-12-05 03:11

    Have a look at how Django-CMS does this, they override the db_table field in the models inheriting from CMSPlugin. The basics (which I also use for my own stuff) boil down to:

    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
    
        ....
    

    You can add some checks, e.g. only update for subclasses (not the direct type), or only update if the value is not customized.

    0 讨论(0)
  • 2020-12-05 03:24

    I have different child classes deriving from the same base class. And I only care for the form view in the Django Admin interface.

    The only solution that worked for me was to customize the Django Admin interface and set the verbose_name (or help_text) there:

    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)
    
    0 讨论(0)
提交回复
热议问题