| 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)
|
|---|