猴子修补 Django 表单类?
给定一个表单类(位于巨型 Django 应用程序深处的某个位置)..
class ContactForm(forms.Form):
name = ...
surname = ...
考虑到您想向此表单添加另一个字段而不扩展或修改表单类本身,为什么以下方法不起作用?
ContactForm.another_field = forms.CharField(...)
(我的第一个猜测是,Django 使用的元类黑客技术仅在第一次构造表单类时适用。如果是这样,是否有办法重新声明该类来克服这个问题?)
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?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一些相关的定义出现在 django/forms/forms.py 中。它们是:
class BaseForm
class Form
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
一样简单。然后,每个表单实例都会获取
base_fields
的deepcopy
,该副本在的
。 HTH。__init__
方法中变为form_instance.fields
基本表单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 fromDeclarativeFieldsMetaclass
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 anOrderedDict
instance with the field name serving as the keys.DeclarativeFieldsMetaclass
then sticks this value in the attributebase_fields
and calls totype
to construct the class. It then passes the class to themedia_property
function inwidgets.py
and attaches the return value to themedia
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 freshMedia
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 intobase_fields
.Each form instance then gets a
deepcopy
ofbase_fields
that becomesform_instance.fields
in the__init__
method ofBaseForm
. HTH.