How to render django form field in template

Victor Proon picture Victor Proon · Nov 16, 2011 · Viewed 28.3k times · Source

I want to make a page with a list of users and checkboxes that signal if a user is selected, which will apply some action to selected users. I created a form class which looks like this:

#in forms.py
class UserSelectionForm(forms.Form):
    """form for selecting users"""
    def __init__(self, userlist, *args, **kwargs):
        self.custom_fields = userlist
        super(forms.Form, self).__init__(*args, **kwargs)
        for f in userlist:
            self.fields[str(f.id)] = forms.BooleanField(initial=False)    

    def get_selected(self):
        """returns selected users"""
        return filter(lambda u: self.fields[str(u.id)], self.custom_fields)

In my template I have users listed in a table and I want the last column of this table to be those checkboxes. I need to render fields one by one depending on their name. I tried creating a template tag that would return the html code of the needed form element:

#in templatetags/user_list_tags.py
from django import template
register = template.Library()

#this is django template tag for user selection form
@register.filter 
def user_select_field(form, userid):
    """
    returns UserSelectionForm field for a user with userid
    """
    key = std(userid)
    if key not in form.fields.keys():
        print 'Key %s not found in dict' % key
        return None
        return form.fields[key].widget.render(form, key)

Finally, here's the template code:

<form action="" method="post">
{% csrf_token %}
<table class="listtable">
    <tr>
    <th>Username</th>
    <th>Select</th>
    </tr>
{% for u in userlist %}
    <tr>
    <td>{{u.username}}</td>
    <td>{{select_form|user_select_field:u.id}}</td>
    </tr>
{% endfor %}
</table>
<p><input type="submit" value="make actions" /></p>

However, this does not bind those widgets to the form and thus, after submitting the form, validation fails. The error message says that all the custom fields are required. So here are my questions:

  1. What is the right way to render separate form fields?

  2. What is the right way of creating such a form with checkboxes? (I mean maybe my method is stupid and there is a much easier way of achieving what I want.

Answer

Chris Pratt picture Chris Pratt · Nov 16, 2011

You're making the template far too complicated. Add a label to each field when you create it in the form's __init__ method.

for f in userlist:
    self.fields[str(f.id)] = forms.BooleanField(label=f.username, initial=False)

Then just loop over the fields in the form and don't worry about the userlist anymore.

{% for field in form %}
<tr>
    <td>{{ field.label_tag }}</td>
    <td>{{ field }}</td>
</tr>
{% endfor %}