使用Django Forms API控制选择输入的级别
我想在使用Django表单API的下拉选择框中,给选项元素添加一个label属性,但又不想覆盖下拉框的render_options方法。请问这样做可能吗?如果可以,应该怎么做呢?
注意:我想直接给选项添加label属性(这在XHTML严格标准中是有效的),而不是给选项组添加。
2 个回答
1
我怕这是不可能的,除非你对Select
这个小部件进行子类化,也就是自己重新定义它的显示方式,正如你所猜的那样。Select的代码并没有为每个<option>
项提供任何属性。它只包含选项的值、是否被选中的状态和标签……就这些了,我很抱歉:
def render_option(option_value, option_label):
option_value = force_unicode(option_value)
selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
return u'<option value="%s"%s>%s</option>' % (
escape(option_value), selected_html,
conditional_escape(force_unicode(option_label)))
2
我刚写了一个类来实现这个功能:
from django.forms.widgets import Select
from django.utils.encoding import force_unicode
from itertools import chain
from django.utils.html import escape, conditional_escape
class ExtendedSelect(Select):
"""
A subclass of Select that adds the possibility to define additional
properties on options.
It works as Select, except that the ``choices`` parameter takes a list of
3 elements tuples containing ``(value, label, attrs)``, where ``attrs``
is a dict containing the additional attributes of the option.
"""
def render_options(self, choices, selected_choices):
def render_option(option_value, option_label, attrs):
option_value = force_unicode(option_value)
selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
attrs_html = []
for k, v in attrs.items():
attrs_html.append('%s="%s"' % (k, escape(v)))
if attrs_html:
attrs_html = " " + " ".join(attrs_html)
else:
attrs_html = ""
return u'<option value="%s"%s%s>%s</option>' % (
escape(option_value), selected_html, attrs_html,
conditional_escape(force_unicode(option_label)))
# Normalize to strings.
selected_choices = set([force_unicode(v) for v in selected_choices])
output = []
for option_value, option_label, option_attrs in chain(self.choices, choices):
if isinstance(option_label, (list, tuple)):
output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
for option in option_label:
output.append(render_option(*option))
output.append(u'</optgroup>')
else:
output.append(render_option(option_value, option_label,
option_attrs))
return u'\n'.join(output)
举个例子:
select = ExtendedSelect(choices=(
(1, "option 1", {"label": "label 1"}),
(2, "option 2", {"label": "label 2"}),
))