问题描述
给定一个表单类(在你的巨型Django应用程序的深处).. class ContactForm(forms.Form)
name = ...
surname = ...
并考虑你希望在此窗体中添加另一个字段,而不需要扩展或修改窗体类本身,为什么以下方法不起作用?
ContactForm.another_field = forms.CharField(...)
(我的第一个猜测是Django使用的元类hackery只能在第一次构建表单类时使用,如果是这样,会有一种方法来重新发送类来克服这个问题?)
某些相关定义发生在 django / forms / forms.py
中。他们是:
-
class BaseForm
-
class Form
-
class DeclarativeFieldsMetaclass
-
def get_declared_fields
get_declared_fields
从
DeclarativeFieldsMetaclass
调用,并构造一个列表,其中的字段实例按其创建计数器排序。然后,将基类中的字段添加到此列表,并将结果作为 OrderedDict
实例返回,其中字段名称作为键。 DeclarativeFieldsMetaclass
然后将该值粘贴到属性 base_fields
中,并调用类型
构造类。然后将类传递到 widgets.py
中的 media_property
函数,并将返回值附加到 media
属性。
media_property
返回一个属性方法重建每个访问的媒体声明。我的感觉是,这不符合这里,但我可能是错的。
无论如何,如果您没有声明媒体
属性(并且没有一个基类),那么它只返回一个新的 Media
实例,没有参数给构造函数,我认为monkeypatching一个新的字段应该简单的手动将字段插入到 base_fields
中。
ContactForm .another_field = forms.CharField(...)
ContactForm.base_fields ['another_field'] = ContactForm.another_field
每个表单实例然后获取一个 deepcopy
base_fields
,成为 form_instance
。 HTH。 BaseForm
的 __ init __
方法中的.fields
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表单类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!