Как переопределить подробное имя поля модели суперкласса в django
Скажем, что у меня есть модель Foo, которая наследуется от SuperFoo:
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 я бы хотел переопределить verbose_name поля имени SuperFoo. Могу я? Если нет, лучший вариант - установить метку внутри определения формы модели, чтобы отобразить ее в шаблоне?
Ответы
Ответ 1
Простой хак, который я использовал, это:
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._meta.get_field('name').verbose_name = 'Whatever'
Ответ 2
Принимая во внимание предостережение, что изменение 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
Приведенный выше пример изменяет verbose_name и help_text для унаследованного поля timestamp. Вы можете передать столько ключевых слов, сколько полей, которые вы хотите изменить.
Ответ 3
Лучше всего было бы установить/изменить ярлык в самой форме. Ссылаясь на поле name
модели Foo
(например, просмотрев его в Foo._meta.fields
), вы действительно дадите ссылку на поле name
SuperFoo
, поэтому изменение его verbose_name
изменится это в обеих моделях.
Кроме того, добавление поля name
в класс Foo
также не будет работать, потому что...
Перекрытие полей в родительской модели приводит к трудностям в таких областях, как инициализация новых экземпляров (указание которое полемизируется в Model.__init__
) и сериализации. Это функции, которые обычные Python Наследование класса не должно с таким же образом, так что разница между моделью Django наследование и класс Python Наследование не просто произвольно.
Ответ 4
Посмотрите, как это делает 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
....
Вы можете добавить некоторые проверки, например. только обновление для подклассов (не прямого типа) или обновление только в том случае, если значение не настроено.