Monkey patching a Django form class?
Given a form class (somewhere deep in your giant Django app).开发者_如何学C.
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.
精彩评论