A widget for selecting from a list of Model
instances using MultipleChoiceField
which renders a table row for each choice, consisting of a column for a checkbox followed by a column for each item specified in item_attrs
, which must specify attributes of the objects passed as choices.
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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))
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Example form:
#
Thanks.
I added the following code to support dictionaries as well:
Please tell me if this could introduce any problems that I'm not seeing.
#
I updated this code for Django 1.8 and Python 3. My code can be found here: https://github.com/willardmr/DjangoTableSelectMultipleWidget. I also posted widgets for selecting a single object and for edit and delete buttons on each object.
#
Please login first before commenting.