Login

TableSelectMultiple Widget

Author:
insin
Posted:
December 19, 2007
Language:
Python
Version:
1.2
Tags:
forms table widget selectmultiple
Score:
3 (after 3 ratings)

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

  1. DisableableSelectWidget by notanumber 2 years, 10 months ago
  2. CheckboxMultiSelect with interable checkboxes by pyramids16 2 years, 4 months ago
  3. CheckboxSelectMultiple that renders in columns by rfugger 4 years, 4 months ago
  4. Tablify templatetag by davidblewett 7 years, 9 months ago
  5. DropDownMultiple widget by marinho 6 years, 10 months ago

Comments

insin (on December 19, 2007):

Example form:

class SelectJobsForInvoiceForm(forms.Form):
    """
    A Form which handles selection of Jobs for invoice.
    """
    jobs = forms.MultipleChoiceField(widget=TableSelectMultiple(
        item_attrs=('formatted_number', 'name', 'client',
                    'get_status_display')))

    def __init__(self, accessible_jobs, *args, **kwargs):
        super(SelectJobsForInvoiceForm, self).__init__(*args, **kwargs)
        self.fields['jobs'].choices = [(j.id, j) \
                                       for j in accessible_jobs]

    def clean(self):
        print self.cleaned_data
        if 'jobs' not in self.cleaned_data or \
           len(self.cleaned_data['jobs']) == 0:
            raise forms.ValidationError(
                u'You must select at least one Job for invoice.')
        return self.cleaned_data

#

StFS (on January 17, 2012):

Thanks.

I added the following code to support dictionaries as well:

     54   for attr in self.item_attrs:
     55       if isinstance(item, dict):
     56           content = item[attr]
     57       elif callable(attr):

Please tell me if this could introduce any problems that I'm not seeing.

#

Please login first before commenting.