猴子修补 Django 表单类? [英] Monkey patching a Django form class?
问题描述
给定一个表单类(在你巨大的 Django 应用程序深处).
class ContactForm(forms.Form):姓名 = ...姓氏 = ...
并且考虑到您想在不扩展或修改表单类本身的情况下向此表单添加另一个字段,为什么以下方法不起作用?
ContactForm.another_field = forms.CharField(...)
(我的第一个猜测是 Django 使用的元类黑客仅在第一次构造表单类时适用.如果是这样,有没有办法重新声明类来克服这个问题?)
一些相关的定义出现在 django/forms/forms.py
中.它们是:
class BaseForm
类表单
class DeclarativeFieldsMetaclass
def get_declared_fields
get_declared_fields
是从 DeclarativeFieldsMetaclass
调用的,并构造一个列表,其中包含按创建计数器排序的字段实例.然后它将基类中的字段添加到此列表中,并将结果作为 OrderedDict
实例返回,字段名称作为键.DeclarativeFieldsMetaclass
然后将此值粘贴在属性 base_fields
中并调用 type
以构造类.然后它将类传递给 widgets.py
中的 media_property
函数,并将返回值附加到新类的 media
属性.>
media_property
返回一个属性方法,该方法在每次访问时重建媒体声明.我的感觉是它在这里无关紧要,但我可能是错的.
无论如何,如果您没有声明 Media
属性(并且没有任何基类这样做),那么它只会返回一个没有参数的新 Media
实例构造函数,我认为猴子修补一个新字段应该像手动将字段插入 base_fields
一样简单.
ContactForm.another_field = forms.CharField(...)ContactForm.base_fields['another_field'] = ContactForm.another_field
每个表单实例然后获取base_fields
的deepcopy
,在__init__
方法中变成form_instance.fields
BaseForm
.哈.
Given a form class (somewhere deep in your giant Django app)..
class ContactForm(forms.Form):
name = ...
surname = ...
And considering you want to add another field to this form without extending or modifying the form class itself, why does not the following approach work?
ContactForm.another_field = forms.CharField(...)
(My first guess is that the metaclass hackery that Django uses applies only the first time the form class is constructed. If so, would there be a way to redeclare the class to overcome this?)
Some pertinent definitions occur in django/forms/forms.py
. They are:
class BaseForm
class Form
class DeclarativeFieldsMetaclass
def get_declared_fields
get_declared_fields
is called from DeclarativeFieldsMetaclass
and constructs a list with the field instances sorted by their creation counter. It then prepends fields from the base classes to this list and returns the result as an OrderedDict
instance with the field name serving as the keys. DeclarativeFieldsMetaclass
then sticks this value in the attribute base_fields
and calls to type
to construct the class. It then passes the class to the media_property
function in widgets.py
and attaches the return value to the media
attribute on the new class.
media_property
returns a property method that reconstructs the media declarations on every access. My feeling is that it wont be relevant here but I could be wrong.
At any rate, if you are not declaring a Media
attribute (and none of the base classes do) then it only returns a fresh Media
instance with no arguments to the constructor and I think that monkeypatching a new field on should be as simple as manually inserting the field into base_fields
.
ContactForm.another_field = forms.CharField(...)
ContactForm.base_fields['another_field'] = ContactForm.another_field
Each form instance then gets a deepcopy
of base_fields
that becomes form_instance.fields
in the __init__
method of BaseForm
. HTH.
这篇关于猴子修补 Django 表单类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!