猴子修补 Django 表单类? [英] Monkey patching a Django form class?

查看:23
本文介绍了猴子修补 Django 表单类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

class ContactForm(forms.Form):姓名 = ...姓氏 = ...

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

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

(我的第一个猜测是 Django 使用的元类黑客仅在第一次构造表单类时适用.如果是这样,有没有办法重新声明类来克服这个问题?)

解决方案

一些相关的定义出现在 django/forms/forms.py 中.它们是:

  1. class BaseForm
  2. 类表单
  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.fieldsBaseForm.哈.

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:

  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.

这篇关于猴子修补 Django 表单类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆