Reputation: 6570
Can someone tell me how to write CustomWidget/CustomField for a checkbox group with drop-downs in it using Django forms?
Ex. Case: Text boxes will show Dimensions and each Dimension should have a drop down with list of aggregate functions in it.
Upvotes: 1
Views: 2117
Reputation: 6570
In forms.py
class DynamicForm(forms.Form):
options = [
('Textbox1', 'Textbox1'),
('Textbox2', 'Textbox2'),
...
]
dynamic_data = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=options)
def __init__(self, *args, **kwargs):
super(DynamicForm, self).__init__(*args, **kwargs)
for i in range(1,len(self.options)+1):
self.fields['dd_func_'+str(i)] = forms.ChoiceField(widget=forms.Select, choices= [
('average', 'average'),
('sum', 'sum')], initial='sum', required=False)
def __getitem__(self, name):
try:
field = self.fields[name]
except KeyError:
raise KeyError('Key %r not found in Form' % name)
return forms.forms.BoundField(self, field, name)
In views.py
from app.forms import DynamicForm
def create_form(request):
if request.method == 'POST':
dynamic_form = DynamicForm(request.POST)
...
...
else:
dynamic_form = DynamicForm()
return render(request, 'form.html', {
'dynamic_form': dynamic_form
})
In templates/form.html
{% load myfilters %}
{{ dynamic_form.dynamic_data.errors }}
{% for checkbox in dynamic_form.dynamic_data|checkboxiterator %}
{{ checkbox }}
{% with c=forloop.counter|stringformat:"s" %}
{% with c='dd_func_'|add:c %}
{{ dynamic_form|lookup:c }}
{% endwith %}
{% endwith %}
{% endfor %}
In templatetags/myfilters.py
https://djangosnippets.org/snippets/2159/
and
@register.filter
def lookup(f, name):
try:
return f[name]
except KeyError:
return None
Upvotes: 0
Reputation: 7185
I'd use MultiValueField and MultiWidget.
You can make the MultiValueField init method accept any options you want to build all the options and use custom logic in the MultiWidget to render all the checkboxes and selects and compress/decompress the values input by the user to a suitable representation, like a dict {checkbox_name: operation}.
Upvotes: 1
Reputation: 1390
If I understand you correctly, this should do it.
Depending on what you have in your views, simply place some list in your_list as context. Depending on how many items there are in the list, it will create one of these checkbox-list combinations for each one.
{% for number in your_list %}
<div class="check_box" id="check_box_{{ number }}">
<input id="cb_{{ number }}" name="cb_{{ number }}" type="checkbox"><label for="cb_{{ number }}">textbox {{ number }}</label>
<select class="some_class">
<option value="1">Sum</option>
<option value="2">Difference</option>
<option value="3">Whatever</option>
</select>
</div>
{% endfor %}
The output will look like this: http://jsfiddle.net/3vetooLp/1/
Upvotes: 0