| 63 | |
| 64 | class GroupedSelect(Select): |
| 65 | def __init__(self, attrs=None, groups=(), choices=()): |
| 66 | super(GroupedSelect, self).__init__(attrs, choices) |
| 67 | # groups maps from 'group name' to a list of values in that group |
| 68 | # to preserve ordering, it's a list-of-tuples instead of a dict |
| 69 | self.groups = groups |
| 70 | |
| 71 | def render(self, name, value, attrs=None, choices=()): |
| 72 | if value is None: value = '' |
| 73 | final_attrs = self.build_attrs(attrs, name=name) |
| 74 | output = [u'<select%s>' % flatatt(final_attrs)] |
| 75 | str_value = smart_unicode(value) # Normalize to string. |
| 76 | allchoices = dict([(smart_unicode(k), smart_unicode(v)) |
| 77 | for k, v in chain(self.choices, choices)]) |
| 78 | for group_label, members in self.groups: |
| 79 | group_label = smart_unicode(group_label) |
| 80 | output.append(u'<optgroup label="%s">' % escape(group_label)) |
| 81 | for option_value in members: |
| 82 | option_value = smart_unicode(option_value) |
| 83 | try: |
| 84 | option_label = allchoices[option_value] |
| 85 | except KeyError: |
| 86 | continue # silently ignore missing elements from the group |
| 87 | selected_html = (option_value == str_value) and u' selected="selected"' or '' |
| 88 | output.append(u'<option value="%s"%s>%s</option>' % (escape(option_value), selected_html, escape(option_label))) |
| 89 | output.append(u'</optgroup>') |
| 90 | output.append(u'</select>') |
| 91 | return u'\n'.join(output) |
| 92 | |