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:
What is the right way to render separate form fields?
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.
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 %}