1 | from django.contrib.admin import util as admin_util
|
---|
2 |
|
---|
3 | class 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 | """
|
---|
7 |
|
---|
8 | def __init__(self, form, field, name, fieldset):
|
---|
9 | super(FieldsetBoundField, self).__init__(form, field, name)
|
---|
10 | self.fieldset = fieldset
|
---|
11 |
|
---|
12 | class 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`.
|
---|
17 |
|
---|
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.
|
---|
20 |
|
---|
21 | It should be listed as the parent class before `django.forms.models.ModelForm` based classes so that methods here take
|
---|
22 | precedence.
|
---|
23 | """
|
---|
24 |
|
---|
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 | """
|
---|
30 |
|
---|
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]
|
---|
37 |
|
---|
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 | """
|
---|
43 |
|
---|
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)
|
---|