MultiForm and MultiModelForm
Based on a PrefixDict class I wrote and thus very lean. Lacks a little documentation, though
class MyMultiForm(ModelMultiForm):
class Meta:
localized_fields = '__all__'
form_classes = OrderedDict((
('form1', Form1),
('form2', Form2),
))
Subfields are named form-name
prefix_sep
subfield-name
. prefix_sep
defaults to -
. For access in templates, use form.varfields
, which uses var_prefix_sep
(default: _
), instead.
multiform.varfields()['form1_field1']
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | # -*- encodung=utf-8 -*-
from collections import OrderedDict
from django.core.exceptions import NON_FIELD_ERRORS
from django.forms import BaseForm
from django.forms.utils import ErrorList
from django.utils.safestring import mark_safe
from .prefixdict import PrefixCombiningDict
class MultiForm(BaseForm):
PREFIX_SEP = '-'
VAR_PREFIX_SEP = '__'
base_fields = {}
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False,
**kwargs
):
self.prefix_sep = self.PREFIX_SEP
self.var_prefix_sep = self.VAR_PREFIX_SEP
super(MultiForm, self).__init__(data=data, files=files,
auto_id=auto_id, prefix=prefix, initial=initial, error_class=error_class, label_suffix=label_suffix,
empty_permitted=empty_permitted
)
self._init_subforms(data=data, initial=initial, label_suffix=label_suffix, **kwargs)
self.fields = PrefixCombiningDict(((prefix, form.fields) for prefix, form in self.forms.iteritems() if form.fields), sep=self.prefix_sep)
def _init_subforms(self, data=None, files=None, auto_id='id_%s',
prefix=None, initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False, **kwargs
):
if not prefix:
prefix = ''
form_classes = self.get_form_classes()
if len(form_classes) == 0:
raise ValueError("Need at least one form class for MultiForm")
forms = OrderedDict()
for key, form_class in form_classes.iteritems():
sub_initial = initial.get(key) if initial else None
sub_prefix = prefix + key
sub_kwargs = {kw_key: kw_value[key] for kw_key, kw_value in kwargs.iteritems() if key in kw_value}
forms[key] = self.create_form(
form_class,
data=data, files=files, auto_id=auto_id,
prefix=sub_prefix, initial=sub_initial, error_class=error_class,
label_suffix=label_suffix, empty_permitted=empty_permitted,
**sub_kwargs
)
self.forms = forms
def create_form(self,
form_class,
data=None, files=None, auto_id=None,
prefix=None, initial=None, error_class=None,
label_suffix=None, empty_permitted=None,
*args, **kwargs
):
return form_class(
data=data, files=files, auto_id=auto_id,
prefix=prefix, initial=initial, error_class=error_class,
label_suffix=label_suffix, empty_permitted=empty_permitted,
*args, **kwargs
)
def full_clean(self):
for form in self.forms.itervalues():
if form:
form.full_clean()
self.cleaned_data = PrefixCombiningDict(
((prefix, form.clean()) for prefix, form in self.forms.iteritems() if form and form.is_valid()),
sep=self.prefix_sep
)
self._errors = {NON_FIELD_ERRORS: []}
for prefix, form in (form for form in self.forms.iteritems() if form):
for field, errors in form.errors.iteritems():
if field == NON_FIELD_ERRORS:
self._errors[NON_FIELD_ERRORS].extend(errors)
else:
self._errors[prefix + self.prefix_sep + field] = errors
return self.cleaned_data
def get_form_classes(self):
try:
return self.form_classes
except NameError:
raise NameError('Subclasses must set form_classes or override get_form_classes()')
def __unicode__(self):
return mark_safe(u"\n".join(unicode(form) for form in self.forms.itervalues()))
def __str__(self):
return mark_safe("\n".join(str(form) for form in self.forms.itervalues()))
def __iter___(self):
for name in self.fields:
yield self[name]
def __getitem__(self, key):
return PrefixCombiningDict(((prefix, form) for prefix, form in self.forms.iteritems() if form), sep=self.prefix_sep)[key]
@property
def varfields(self):
return PrefixCombiningDict(((prefix, form) for prefix, form in self.forms.iteritems() if form), sep=self.var_prefix_sep)
def is_valid(self):
self.full_clean()
return all(form.is_valid() for form in self.forms.itervalues())
class ModelMultiForm(MultiForm):
def create_form(self,
form_class,
data=None, files=None, auto_id=None,
prefix=None, initial=None, instance=None,
error_class=None, label_suffix=None, empty_permitted=None,
*args, **kwargs
):
if instance:
return form_class(data=data, prefix=prefix, initial=initial, instance=instance, *args, **kwargs)
else:
return form_class(data=data, prefix=prefix, initial=initial, *args, **kwargs)
@property
def instance(self):
return dict((prefix, form.instance) for prefix, form in self.forms.iteritems() if form)
def save(self, commit=True):
return dict((key, form.save(commit=commit)) for key, form in self.forms.iteritems() if form)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
create a simple example of how to use it
#
Please login first before commenting.