Created
February 9, 2011 04:59
-
-
Save insin/817906 to your computer and use it in GitHub Desktop.
TableSelectMultiple Widget for Django forms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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. | |
""" | |
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)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment