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

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

问题描述

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

  class ContactForm(forms.Form) 
name = ...
surname = ...

并考虑你希望在此窗体中添加另一个字段,而不需要扩展或修改窗体类本身,为什么以下方法不起作用?

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

(我的第一个猜测是Django使用的元类hackery只能在第一次构建表单类时使用,如果是这样,会有一种方法来重新发送类来克服这个问题?)

解决方案

某些相关定义发生在 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 中,并调用类型构造类。然后将类传递到 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 BaseForm __ init __ 方法中的.fields 。 HTH。


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天全站免登陆