猴子修补 Django 表单类?

发布于 2024-09-27 06:14:50 字数 349 浏览 10 评论 0原文

给定一个表单类(位于巨型 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小梨窩很甜 2024-10-04 06:14:50

一些相关的定义出现在 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 来构造该类。然后,它将类传递给 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_fieldsdeepcopy,该副本在 __init__ 方法中变为 form_instance.fields基本表单。 HTH。

Some pertinent definitions occur in django/forms/forms.py. They are:

  1. class BaseForm
  2. class Form
  3. class DeclarativeFieldsMetaclass
  4. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文