I want to be able to show the list of models on the page, and allow the user to select a few of them at the same time.
For example, say I have a user selection screen, for the model:
class User(model):
first = # char field
last = # char field
birthdate = # date
Then I want to show the users and let them select one of them:
Please select users:
[] John Smith Jan, 2001
[] Mike Davis Feb, 2002
[] John Doe Dec, 2000
[Continue]
This form will then get POSTed and processed.
One way I can think of doing it is with ModelFormset. The problem is when I try to use the ModelFormsets for displaying the users, I can't add the check-box.
Another way I can think of is to create a form, and output on it a whole bunch of checkboxes with a particular id. Then on submit - iterate over all selected checkboxes. Not sure how that would work with Django's forms.
Any suggestions are welcome. Thanks.
EDIT: Well it turns out that by giving each check box an ID (for example patient id) within the same name group and simply looking at POST dictionary in the django view gives me exactly what i need!
I created a custom SelectMultiple widget for displaying object details along with a checkbox for selection back when forms was still called newforms - it still seem to work:
from django.forms import CheckboxInput, SelectMultiple
from django.utils.encoding import force_unicode
from django.utils.html import escape
from django.utils.safestring import mark_safe
class TableSelectMultiple(SelectMultiple):
"""
Provides selection of items via checkboxes, with a table row
being rendered for each item, the first cell in which contains the
checkbox.
When providing choices for this field, give the item as the second
item in all choice tuples. For example, where you might have
previously used::
field.choices = [(item.id, item.name) for item in item_list]
...you should use::
field.choices = [(item.id, item) for item in item_list]
"""
def __init__(self, item_attrs, *args, **kwargs):
"""
item_attrs
Defines the attributes of each item which will be displayed
as a column in each table row, in the order given.
Any callables in item_attrs will be called with the item to be
displayed as the sole parameter.
Any callable attribute names specified will be called and have
their return value used for display.
All attribute values will be escaped.
"""
super(TableSelectMultiple, self).__init__(*args, **kwargs)
self.item_attrs = item_attrs
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
has_id = attrs and 'id' in attrs
final_attrs = self.build_attrs(attrs, name=name)
output = []
str_values = set([force_unicode(v) for v in value]) # Normalize to strings.
for i, (option_value, item) in enumerate(self.choices):
# If an ID attribute was given, add a numeric index as a suffix,
# so that the checkboxes don't all have the same ID attribute.
if has_id:
final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value)
output.append(u'<tr><td>%s</td>' % rendered_cb)
for attr in self.item_attrs:
if callable(attr):
content = attr(item)
elif callable(getattr(item, attr)):
content = getattr(item, attr)()
else:
content = getattr(item, attr)
output.append(u'<td>%s</td>' % escape(content))
output.append(u'</tr>')
return mark_safe(u'\n'.join(output))
Example form:
class JobSelectionForm(forms.Form):
jobs = forms.MultipleChoiceField(widget=TableSelectMultiple(
item_attrs=('formatted_number', 'name', 'client', 'get_status_display')))
def __init__(self, accessible_jobs, *args, **kwargs):
super(JobSelectionForm, self).__init__(*args, **kwargs)
self.fields['jobs'].choices = [(j.id, j) \
for j in accessible_jobs]
With the above form, you would pass the list of items to be displayed as the first argument when instantiating your form object.
Template:
{% if form.jobs.errors %}{{ form.jobs.errors }}{% endif %}
<table>
<thead>
<tr>
<th> </th>
<th>Number</th>
<th>Name</th>
<th>Client</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{{ form.jobs }}
</tbody>
</table>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With