Ticket #6630: metaforms.py

File metaforms.py, 2.2 KB (added by Mitar, 14 years ago)

A simple approach to fieldsets

1from django.contrib.admin import util as admin_util
3class FieldsetBoundField(forms.BoundField):
4 """
5 This class extends `django.forms.forms import.BoundField` to also carry information about the fieldset this field is in.
6 """
8 def __init__(self, form, field, name, fieldset):
9 super(FieldsetBoundField, self).__init__(form, field, name)
10 self.fieldset = fieldset
12class FieldsetFormMixin(object):
13 """
14 This mixin class defines methods to use with other form classes to extend them to return `FieldsetBoundField` when accessing
15 forms' fields. If such form class has `fieldset` attribute defined it is used to attach fieldset to all fields, which
16 are returned as `FieldsetBoundField`.
18 `fieldset` attribute should have the same structure as that for `django.contrib.admin.ModelAdmin`. The attached fieldset is
19 the given fieldset dictionary with `name` set to the name of the fieldset.
21 It should be listed as the parent class before `django.forms.models.ModelForm` based classes so that methods here take
22 precedence.
23 """
25 def __iter__(self):
26 """
27 If `fieldset` attribute is not defined we iterate normally. Otherwise we iterate in the order in which fields
28 are defined in `fieldset` attribute. In the later case we return fields as `FieldsetBoundField`.
29 """
31 if not hasattr(self, 'fieldset'):
32 for field in super(FieldsetFormMixin, self).__iter__():
33 yield field
34 else:
35 for field in admin_util.flatten_fieldsets(self.fieldset):
36 yield self[field]
38 def __getitem__(self, name):
39 """
40 If `fieldset` attribute is not defined we return the field normally. Otherwise we return the field as `FieldsetBoundField`
41 with fieldset attached to it. It the later case the field has to be defined in `fieldset` attribute.
42 """
44 field = super(FieldsetFormMixin, self).__getitem__(name)
45 if not hasattr(self, 'fieldset'):
46 return field
47 else:
48 fieldset = None
49 for fname, fset in self.fieldset:
50 if name in fset['fields']:
51 # We copy dictionary here so that we do not dirty it with later changes
52 fieldset = fset.copy()
53 fieldset['name'] = fname
54 break
55 if not fieldset:
56 raise KeyError('Key %r not defined in any fieldset in Form' % name)
57 return FieldsetBoundField(self, field.field, field.name, fieldset)
Back to Top