やりたかったこと、解決方針
WTFormsでselect
にplaceholder
を付けたかった。
Bootstrapを入れているので単にoption
にclass="hidden"
を入れれば良いが、htmlはwtf.quickForm
を使いたかったので、Formクラスでなんとかならないかを調べた。
調べた結果Fieldクラスを作らないとダメそうだったので、どうせならclass属性だけじゃなくなんでも入れられるようにしたくなった。
環境
- python 3.6.7
- WTForms 2.2.1
- flask-Bootstrap 3.3.7.1
ソース
WTForms.SelectField
とWTForms.widgets.Select
を拡張した
field.py
from flask_wtf import FlaskForm
from wtforms import SelectField
from wtforms.widgets import Select, HTMLString, html_params
# WTForms.widgets.Selectを拡張
class SelectHasAttributesOption(Select):
def __call__(self, field, **kwargs):
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 val, label, selected, render_kw in field.iter_choices_with_render_kw(): # 追加:render_kw 変更:iter_choices_with_render_kw
html.append(self.render_option(val, label, selected, **render_kw)) # 追加:**render_kw
html.append('</select>')
return HTMLString(''.join(html))
# WTForms.SelectFieldを拡張
class SelectHasAttributesOptionField(SelectField):
widget = SelectHasAttributesOption()
def iter_choices(self):
for value, label, *_ in self.choices:
yield (value, label, self.coerce(value) == self.data)
def pre_validate(self, form):
for v, *_ in self.choices:
if self.data == v:
break
else:
raise ValueError(self.gettext('Not a valid choice'))
def iter_choices_with_render_kw(self):
for value, label, *render_kw in self.choices:
render_kw = render_kw[0] if render_kw else {}
yield (value, label, self.coerce(value) == self.data, render_kw)
使い方
SelectField
の代わりにSelectHasAttributesOptionField
を使い、choices
のタプルにrender_kw的に辞書を追加する。
ソース
from flask_wtf import FlaskForm
from .field import SelectHasAttributesOptionField
class TestForm(FlaskForm):
select = SelectHasAttributesOptionField(
'ラベル',
choices=[
('', '選択して', {'class': 'hidden'}),
('1', '1'),
('2', '2')
]
)