Problem: You want to render an arbitrary number of fields assigned dynamically, as in snippet #27, but using multiple if
statements in a template would be tedious.
Solution: newforms BoundField
The example demonstrates a form with medication fields. We don't know in advance how many meds will be prescribed to a patient, but we want to display a minimum of 4 medication fields, each consisting of a label, name, and dosage.
My code uses a cheap hack of assigning a .bf attribute to the fields during init, but it's easy to render in a template loop: {% for med in form.med_list %}
Special thanks to Honza for advice on BoundField.
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 | from django import newforms as forms
from django.newforms.forms import BoundField
from django.template import Context, Template
class MedForm(forms.Form):
"""Dynamically assigned/rendered newforms fields using BoundField
>>> m = MedForm({'med_1':"Lipitor",'dosage_1':"80mg QHS PO", \
'med_2':"Lasix",'dosage_2':"40mg QD PO"})
>>> t = Template('''{% for med in form.med_list %}
... {{med.name.label}}: {{ med.name.bf }} {{ med.dosage.bf }}
... {% endfor %}''')
>>> print t.render(Context({'form':m}))
<BLANKLINE>
med_1: <input type="text" name="med_1" value="Lipitor" id="id_med_1" /> <input type="text" name="dosage_1" value="80mg QHS PO" id="id_dosage_1" />
<BLANKLINE>
med_2: <input type="text" name="med_2" value="Lasix" id="id_med_2" /> <input type="text" name="dosage_2" value="40mg QD PO" id="id_dosage_2" />
<BLANKLINE>
med_3: <input type="text" name="med_3" id="id_med_3" /> <input type="text" name="dosage_3" id="id_dosage_3" />
<BLANKLINE>
med_4: <input type="text" name="med_4" id="id_med_4" /> <input type="text" name="dosage_4" id="id_dosage_4" />
<BLANKLINE>
>>>
"""
def __init__(self, *args, **kwargs):
number_of_meds = kwargs.pop('number_of_meds', 4)
super(MedForm, self).__init__(*args, **kwargs)
self.med_list = []
for i in range(1, number_of_meds+1):
k1 = 'med_%d' % i
self.fields[k1] = forms.CharField(required=False, label=k1)
self.fields[k1].bf = BoundField(self, self.fields[k1], k1)
k2 = 'dosage_%d' % i
self.fields[k2] = forms.CharField(required=False, label=k2)
self.fields[k2].bf = BoundField(self, self.fields[k2], k2)
self.med_list.append({'name': self.fields[k1],
'dosage': self.fields[k2]})
if __name__ == '__main__':
import doctest
doctest.testmod()
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
This is a cool idea. When editing a page, how do you fill in the values you've already seen?
#
How do you propose to validate data ? In my case cleaned_data dictionary is empty.
#
Please login first before commenting.