returns a list of (argname, value) tuples
(NB: keeps ordering and is easily turned into a dict).
Params:
* tagname : the name of calling tag (for error messages)
* bits : sequence of tokens to parse as kw args
* args_spec : (optional) dict of argname=>validator for kwargs, cf below
* restrict : if True, only argnames in args_specs will be accepted
If restrict=False and args_spec is None (default), this will just try
to parse a sequence of key=val strings.
About args_spec validators :
* A validator can be either a callable, a regular expression or None.
* If it's a callable, the callable must take the value as argument and
return a (possibly different) value, which will become the final value
for the argument. Any exception raised by the validator will be
considered a rejection.
* If it's a regexp, the value will be matched against it. A failure
will be considered as a rejection.
* Using None as validator only makes sense with the restrict flag set
to True. This is useful when the only validation is on the argument
name being expected.
- template
- tag
- custom
- template_tags
**NOTE**: Further development of this snippet will take place in the [django-form-utils](http://launchpad.net/django-form-utils) project.
This snippet provides BetterForm and BetterModelForm classes which are subclasses of django.forms.Form and django.forms.ModelForm, respectively. BetterForm and BetterModelForm allow subdivision of forms into fieldsets which are iterable from a template, and also allow definition of row_attrs which can be accessed from the template to apply attributes to the surrounding container of a specific form field.
It's frequently said that a generic form layout template is a pipe dream and in "real usage" it's necessary to manually layout forms, but in my experience the addition of fieldsets and row_attrs, plus a competent CSS designer, make it possible to create a generic template that can render useful production form markup in 95+% of cases.
Usage:
class MyForm(BetterForm):
one = forms.CharField()
two = forms.CharField()
three = forms.CharField()
class Meta:
fieldsets = (('main', {'fields': ('two',), 'legend': ''}),
('Advanced', {'fields': ('three', 'one'),
'description': 'advanced stuff'}))
row_attrs = {'one': {'style': 'display: none'}}
Then in the template:
{% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %}
{% for fieldset in form.fieldsets %}
<fieldset class="fieldset_{{ fieldset.name }}">
{% if fieldset.legend %}
<legend>{{ fieldset.legend }}</legend>
{% endif %}
{% if fieldset.description %}
<p class="description">{{ fieldset.description }}</p>
{% endif %}
<ul>
{% for field in fieldset %}
{% if field.is_hidden %}
{{ field }}
{% else %}
<li{{ field.row_attrs }}>
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
</li>
{% endif %}
{% endfor %}
</ul>
</fieldset>
{% endfor %}