Opened 16 years ago
Last modified 3 years ago
#10874 new New feature
ModelFormMetaclass does not provide easy way of extending
Reported by: | wombat | Owned by: | nobody |
---|---|---|---|
Component: | Forms | Version: | 1.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I am currently creating an extension to the ModelForm that provides similar features to Admin such as fieldsets. Unfortunately, the ModelFormMetaclass does not provide easy way of extending ModelForm. For example, I need to access meta information for fieldsets and dynamicaly flatten to fields before method fields_for_model is called. Also, what if I wanted to override fields for model. There is no way of doing this without completely overriting the entire ModelFormMetaclass. It seems that the meta class approach initialization does not support granual overriding of logic. I have made the following code change to django ModelFormMetaclass to ease my pain for now. However, in the long run it may not be enought.
class ModelFormMetaclass(type): .... options_class = attrs.pop('options_class', ModelFormOptions) opts = new_class._meta = options_class(getattr(new_class, 'Meta', None)) ...
The following is the code that uses this:
class DynamicModelFormOptions(ModelFormOptions): def __init__(self, options=None): super(DynamicModelFormOptions,self).__init__(options) self.fieldsets = getattr(options, 'fieldsets', None) self.fieldwidths = getattr(options, 'fieldwidths', None) if self.fieldsets: self.fields = flatten_fieldsets(self.fieldsets) class DynamicModelFormMetaclass(ModelFormMetaclass): def __new__(cls, name, bases, attrs): attrs['formfield_callback'] = formfield_for_dbfield attrs['options_class'] = DynamicModelFormOptions new_class = super(DynamicModelFormMetaclass, cls).__new__(cls, name, bases, attrs) #new_class._meta = DynamicModelFormOptions(getattr(new_class, 'Meta', None)) #assign_default_widgets(new_class.base_fields) return new_class
Change History (6)
comment:1 by , 15 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → Bug |
comment:3 by , 14 years ago
Type: | Bug → New feature |
---|
On second thoughts, this is more an additional feature.
comment:6 by , 3 years ago
For anyone looking for a way to extend ModelFormOptions with their own options, I found this recipe works well: https://github.com/wagtail/django-permissionedforms/blob/main/permissionedforms/forms.py
There's a slight bit of ugliness in the implementation, in that ModelFormMetaclass builds a ModelFormOptions instance to do its own thing, which then gets thrown away and replaced with the custom ModelFormOptions subclass, meaning that the ModelFormOptions constructor ends up running for a second time. This could be avoided if ModelFormMetaclass were to look for an options_class
attribute on either the target class (as per above) or itself (as per my implementation).
(Even better, Django could move the 'collect options from an inner Meta class' logic into a mixin as I've done, so that the pattern of having various form mixin classes contribute their own options can happen with or without ModelForm. But given the lack of activity on this issue, that's probably too niche an interest to be worth the disruption :-) )
I don't think this is the right approach, but it could be made more modular.