Обезьяна исправляет класс формы Django? - PullRequest
6 голосов
/ 14 октября 2010

Учитывая класс формы (где-то глубоко в вашем гигантском приложении Django) ..

class ContactForm(forms.Form):
    name = ...
    surname = ...

И учитывая, что вы хотите добавить другое поле к этой форме без расширения или изменения самого класса формы , почему не работает следующий подход?

ContactForm.another_field = forms.CharField(...)

(Мое первое предположение состоит в том, что хакерство метакласса, которое использует Django, применяется только при первом создании класса формы. Если это так, будет лиспособ переопределить класс, чтобы преодолеть это?)

1 Ответ

8 голосов
/ 14 октября 2010

Некоторые соответствующие определения встречаются в django/forms/forms.py. Это:

  1. class BaseForm
  2. class Form
  3. class DeclarativeFieldsMetaclass
  4. def get_declared_fields

get_declared_fields вызывается из DeclarativeFieldsMetaclass и создает список с экземплярами полей, отсортированными по их счетчику создания. Затем он добавляет поля из базовых классов в этот список и возвращает результат в виде OrderedDict экземпляра с именем поля, которое служит ключом. DeclarativeFieldsMetaclass затем вставляет это значение в атрибут base_fields и вызывает type для создания класса. Затем он передает класс в функцию media_property в widgets.py и присоединяет возвращаемое значение к атрибуту media в новом классе.

media_property возвращает метод свойства, который восстанавливает объявления мультимедиа при каждом доступе. У меня такое ощущение, что здесь это не будет актуально, но я могу ошибаться.

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

ContactForm.another_field = forms.CharField(...)
ContactForm.base_fields['another_field'] = ContactForm.another_field

Каждый экземпляр формы получает deepcopy из base_fields, который становится form_instance.fields в методе __init__ из BaseForm. НТН.

...