我正在尝试创建SelectField
或SelectMultipleField
,以便我可以为其<option>
标记添加属性。我正在尝试添加data-id
或其他data-____
等属性。我无法弄清楚如何执行此操作,因为似乎只能将属性添加到<select>
标记本身而不是选项。
最终结果应该是这样的:
<select id="regularstuff-here" name="regular-name-here">
<option value="1" data-id="somedata here" >Some Name here</option>
<option value="2" data-id="somedata here" >Some Name here</option>
</select>
我假设我必须创建一个自定义小部件。如果我查看WTForms的源代码,我会看到select
小部件调用:
html.append(self.render_option(val, label, selected))
如果我看一下这种方法:
@classmethod
def render_option(cls, value, label, selected, **kwargs):
options = dict(kwargs, value=value)
if selected:
options['selected'] = True
return HTMLString('<option %s>%s</option>' % (html_params(**options),
escape(text_type(label))))
因此,您似乎无法将任何额外的参数传递给呈现option
标记的方法。
答案 0 :(得分:3)
我只是想说,如果没有猴子修补或重写wtforms,这是可能的。库代码确实支持它,虽然不是很直接。我发现这个是因为我试图为WTForms编写一个修复程序并自己提交了一个公关,然后发现你可以这样做(我花了几天时间试图解决这个问题):
>>> from wtforms import SelectField, Form
>>> class F(Form):
... a = SelectField(choices=[('a', 'Apple'), ('b', 'Banana')])
...
>>> i = 44
>>> form = F()
>>> for subchoice in form.a:
... print subchoice(**{'data-id': i})
... i += 1
...
<option data-id="44" value="a">Apple</option>
<option data-id="45" value="b">Banana</option>
请参阅此处的convo:
https://github.com/wtforms/wtforms/pull/81
答案 1 :(得分:2)
如果你(像我一样)希望将自定义属性存储在选择数组中,每个选项,而不是在渲染时提供,以下自定义&#34; AttribSelectField&#34;和小部件应该有所帮助选项变为(value,label,render_args)的3元组,而不是(value,label)的2元组。
from wtforms.fields import SelectField
from wtforms.widgets import Select, html_params, HTMLString
class AttribSelect(Select):
"""
Renders a select field that supports options including additional html params.
The field must provide an `iter_choices()` method which the widget will
call on rendering; this method must yield tuples of
`(value, label, selected, html_attribs)`.
"""
def __call__(self, field, **kwargs):
kwargs.setdefault('id', field.id)
if self.multiple:
kwargs['multiple'] = True
html = ['<select %s>' % html_params(name=field.name, **kwargs)]
for val, label, selected, html_attribs in field.iter_choices():
html.append(self.render_option(val, label, selected, **html_attribs))
html.append('</select>')
return HTMLString(''.join(html))
class AttribSelectField(SelectField):
widget = AttribSelect()
def iter_choices(self):
for value, label, render_args in self.choices:
yield (value, label, self.coerce(value) == self.data, render_args)
def pre_validate(self, form):
if self.choices:
for v, _, _ in self.choices:
if self.data == v:
break
else:
raise ValueError(self.gettext('Is Not a valid choice'))
答案 2 :(得分:0)
作为Mark答案的替代方法,这是一个自定义窗口小部件(字段“ renderer”),允许在渲染时传递选项属性。
from markupsafe import Markup
from wtforms.widgets.core import html_params
class CustomSelect:
"""
Renders a select field allowing custom attributes for options.
Expects the field to be an iterable object of Option fields.
The render function accepts a dictionary of option ids ("{field_id}-{option_index}")
which contain a dictionary of attributes to be passed to the option.
Example:
form.customselect(option_attr={"customselect-0": {"disabled": ""} })
"""
def __init__(self, multiple=False):
self.multiple = multiple
def __call__(self, field, option_attr=None, **kwargs):
if option_attr is None:
option_attr = {}
kwargs.setdefault("id", field.id)
if self.multiple:
kwargs["multiple"] = True
if "required" not in kwargs and "required" in getattr(field, "flags", []):
kwargs["required"] = True
html = ["<select %s>" % html_params(name=field.name, **kwargs)]
for option in field:
attr = option_attr.get(option.id, {})
html.append(option(**attr))
html.append("</select>")
return Markup("".join(html))
声明字段时,将CustomSelect
的实例作为widget
参数。
customselect = SelectField(
"Custom Select",
choices=[("option1", "Option 1"), ("option2", "Option 2")],
widget=CustomSelect(),
)
在调用要渲染的字段时,传递选项ID的字典(“ {field_id}-{option_index}”),该字典定义了要传递给选项的属性的字典。
form.customselect(option_attr={"customselect-0": {"data-id": "value"} })