Login

Render dynamically assigned fields in a template

Author:
rubic
Posted:
March 5, 2007
Language:
Python
Version:
Pre .96
Score:
2 (after 2 ratings)

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

  1. Template tag - list punctuation for a list of items by shapiromatron 3 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 11 months ago
  5. Help text hyperlinks by sa2812 11 months, 3 weeks ago

Comments

skitch (on June 26, 2007):

This is a cool idea. When editing a page, how do you fill in the values you've already seen?

#

kladfaibs (on November 14, 2007):

How do you propose to validate data ? In my case cleaned_data dictionary is empty.

#

Please login first before commenting.