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

Как вы динамически обновляете поля класса Django Form Meta из конструктора формы?

Я хочу динамически обновлять Meta.fields. Можно ли это сделать из конструктора формы? Я попробовал следующее, но year не отображается во время создания формы. Отображаются только name и title.

class Author(models.Model):
    name = ...
    title = ...
    year = ...

class PartialAuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title')

    def __init__(self, *args, **kwargs):
        self.Meta.fields += ('year',)
4b9b3361

Ответ 1

Нет, это не сработает. Мета анализируется - удивительно - метаклассом, прежде чем вы даже дойдете до __init__.

Способ сделать это - добавить поле вручную в self.fields:

def __init__(self, *args, **kwargs):
    super(PartialAuthorForm, self).__init__(*args, **kwargs)
    self.fields['year'] = forms.CharField(whatever)

Ответ 2

Ответы других - великие (особенно @BranHandleys), но иногда их проще всего условно удалить что-то. Очевидно, что это не работает с вещами, которые динамически создаются, но если вам нужно только указать поле или нет, тогда попробуйте сделать это следующим образом.

class MyModelForm(ModelForm):
  class Meta:
    model = MyModel
    fields = ['normalField', 'conditionalField', ]

  def __init__(self, *args, **kwargs):

    super(MyModelForm, self).__init__(*args, **kwargs)

    if condition is True:
      del self.fields['conditionalField']

Выполнение этого по-другому может быть довольно сложным, как указано выше, но условно отбросить его довольно просто. =)

Ответ 3

Ответы на использование __init__ будут работать, но вы потеряете соединение с моделью (при условии, что поле, которое вы добавляете, находится на модели). Вместо этого вы можете динамически создавать новую форму, которая наследуется от существующей формы.

def my_form_factory:
    class ModifiedAuthorForm(PartialAuthorForm):
        class Meta(PartialAuthorForm.Meta):
            fields = PartialAuthorForm.Meta.fields
            if hasattr(fields, 'append'):
                fields.append('year')
            else:
                fields = fields + ('year',)
return ModifiedAuthorForm

Конечно, если вы хотите быть надежным, вероятно, вы должны проверить, что добавленное поле еще не находится в fields, и вы, вероятно, должны также обрабатывать exclude.

Ответ 4

Внутренний класс Meta уже обрабатывается, когда класс ModelForm создается через метакласс, который до того, как создается экземпляр. Выполнение того, что вы пытаетесь сделать в __init__, не будет работать так! Вы можете получить доступ к созданным объектам поля в справочнике self.fields например. вы можете сделать что-то вроде self.fields['year'] = forms.MyFormField(...).

Ответ 5

Добавление поля в форму модели путем переопределения формы __init__ метод не будет работать, поскольку поля формы модели инициализируются перед вызовом конструктора формы. Таким образом, вы не получите никаких значений от фактической модели до формы, и ваши значения не будут сохранены в db после сохранения вызова.

Вам нужно использовать полную красоту python и использовать декоратор класса следующим образом:)

def year_decorator(form_class):
    class ModifiedForm(form_class):
        class Meta(form_class.Meta):
            if isinstance(form_class.Meta.model, Author):
                fields = form_class.Meta.fields + ('year',)
    return ModifiedForm


@year_decorator
class PartialAuthorForm(ModelForm):
    class Meta:
         model = Author
         fields = ('name', 'title')