Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing a dynamic number of fields in a template in django

It is all very simple. I have this form:

class add_basketForm(forms.Form):
def __init__(self, selected_subunits, *args, **kwargs):


    self.selected_subunits = selected_subunits
    super(add_basketForm, self).__init__(*args, **kwargs)

    for subunit in self.selected_subunits:
        self.fields['su%d' % (subunit['unit__id'])] = forms.IntegerField()

The number of subunits are unknown. I would like to use something like this (you get the idea):

{% for unit in selected_subunits %}
  {{ form.su%s }} % (unit.unit__id)
{% endfor %}

But of course that doesn't work. My question is how do I reference those formfields in Django template language?

like image 889
Brian Avatar asked Jan 05 '11 12:01

Brian


3 Answers

In order to access the BoundField instances for your dynamic field instances, which is what gives you access to all of the attributes and methods necessary to render the field, you need to access the field objects using the form of form.fieldname rather than form.fields[fieldname]

Here's a potential refactoring of your form class:

class add_basketForm(forms.Form):
    def __init__(self, selected_subunits, *args, **kwargs):
        super(add_basketForm, self).__init__(*args, **kwargs)
        for subunit in self.selected_subunits:
            self.fields['su%d' % (subunit['unit__id'])] = forms.IntegerField()

    def su_fields(self):
        for name in self.fields:
            if name.startswith('su'):
                yield(self[name])

Then in your template, you should be able to iterate over the fields as you would normally expect by accessing form.su_fields:

{% for su_field in form.su_fields %}
....
{% endfor %}

(I had been struggling with this same problem for several hours. Thanks to this answer from Carl Meyer and this article on dynamic form generation from Jacob Kaplan-Moss for pointing me in the right directions.)

like image 120
gravelpot Avatar answered Nov 10 '22 13:11

gravelpot


Group those fields in an additional list and then simply iterate over this list.

In __init__:

self.subunit_list = []
for subunit in self.selected_subunits:
        field = forms.IntegerField()
        self.fields['su%d' % (subunit['unit__id'])] = field
        self.subunit_list.append(field)

In template:

{% for field in form.subunit_list %}
  ...
{% endfor %}
like image 4
gruszczy Avatar answered Nov 10 '22 13:11

gruszczy


To correct gruszczy's answer, this code worked for me:

In __init__ of your form:

self.subunit_list = []
for subunit in self.selected_subunits:
        field = forms.IntegerField()
        self.fields['su%d' % (subunit['unit__id'])] = field
        self.subunit_list.append(self['su%d' % (subunit['unit__id'])])

In your template:

{% for field in form.subunit_list %}
  <!-- show form field (inputbox) -->
  {{ field }}
{% endfor %}
like image 1
rom Avatar answered Nov 10 '22 13:11

rom