修补Django表单类的猴子?

时间:2010-10-14 06:05:56

标签: python django django-forms monkeypatching

给出一个表单类(在你的巨型Django应用程序的某个深处)..

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

考虑到你想在没有扩展或修改表单类本身的情况下向该表单添加另一个字段,为什么以下方法不起作用?

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

(我的第一个猜测是,Django使用的元类hackery仅在第一次构造表单类时应用。如果是这样,是否有办法重新声明类以克服这个问题?)

1 个答案:

答案 0 :(得分:8)

django/forms/forms.py中出现了一些相关的定义。他们是:

  1. class BaseForm
  2. class Form
  3. class DeclarativeFieldsMetaclass
  4. def get_declared_fields
  5. 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方法{{1}}。 HTH。