Подтвердить что ты не робот

Как переопределить подробное имя поля модели суперкласса в 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. Могу я? Если нет, лучший вариант - установить метку внутри определения формы модели, чтобы отобразить ее в шаблоне?

4b9b3361

Ответ 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

    ....

Вы можете добавить некоторые проверки, например. только обновление для подклассов (не прямого типа) или обновление только в том случае, если значение не настроено.