Say I have a form with 20 fields, and I want to put 10 of these fields (group1) in a particular div environment and the other 10 fields (group2) in a different div environme
Any logical way to group fields would work... say you have a method on your form that returns form fields that you explicitly group?
To save typing, perhaps a certain field prefix naming scheme?
class MyForm(forms.Form):
group1_field = forms.CharField()
group1_field = forms.CharField()
group2_field = forms.CharField()
group2_field = forms.CharField()
def group1(self):
return [self[name] for name in filter(lambda x: x.startswith('group1_'), self.fields.values()]
Perhaps set an attribute on the field you can filter by?
class MyForm(forms.Form):
field = forms.CharField()
field.group = 1
field2 = forms.CharField()
field2.group = 2
def group1(self):
return filter(lambda x: x.group == 1, self.fields.values())
def group2(self):
return filter(lambda x: x.group == 2, self.fields.values())
You could also use the regroup tag if you set these attributes.
{% regroup form.fields by group as field_group %}
{% for group in field_group %}
<div class="group_{{ group.grouper }}">
{% for field in group.list %}
{{ field }}
{% endfor %}
</div>
{% endfor %}
Here's a relevant SO question: Django and Fieldsets on Modelform, though this seems a bit overkill for what I'm looking to accomplish. Also, here's one possible hack, although I'm curious to hear how Django experts solve this problem.
(0) Define a python fieldset object that is iterable so we can iterate over it in a django template:
from django.forms.forms import BoundField
class FieldSet(object):
def __init__(self,form,fields,legend='',cls=None):
self.form = form
self.legend = legend
self.fields = fields
self.cls = cls
def __iter__(self):
for name in self.fields:
field = self.form.fields[name]
yield BoundField(self.form, field, name)
(1) In the view use:
fieldsets = (FieldSet(form_object, ('field_name1','field_name2'),
legend='Div env 1',
cls="class1"),
FieldSet(form_object, ('field_name3','field_name4'),
legend="Div env 2",
cls="class2"))
return render_to_response('my_form.html',
{'form': form_object,'fieldsets':fieldsets},
context_instance=RequestContext(request))
(2) Now in the template do:
{% for set in fieldsets %}
<fieldset{% if set.cls %} class="{{ set.cls }}"{% endif %}>
<legend>{{ set.legend }}</legend>
{% for field in set %}
{{ field.label}} : {{ field }}
{% endfor %}
</fieldset>
{% endfor %}
Note that it is possible to replace the fieldset
tag with a div
tag to address my specific question.
+++ Much of this answer extracted from this blog post by Michael Kowalchik. +++
I finally was able to bring @Yuji'Tomita'Tomitas regroup-template-tag-solution to work (see comments in @Yuji'Tomita'Tomitas answer to understand difficulties). I think this is really a nice and easy way to perfom grouping of fields!
The solution was to regroup via group
attribute of field accessing the field
attribute of returned BoundFields
. Minimal example:
In forms.py :
class TestForm(Form):
a = IntegerField()
a.group = 1
b = IntegerField()
b.group = 1
c = IntegerField()
c.group = 2
d = IntegerField()
d.group = 2
In template:
<form>
{% csrf_token %}
{% regroup form by field.group as field_groups %}
{% for field_group in field_groups %}
{{field_group.grouper}}
{% for field in field_group.list %}
{{field}}
{% endfor %}
{% endfor %}
</form>