2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WTFormsのSelectFieldを動的に使う。

Last updated at Posted at 2020-07-23

FlaskでWTFormsでフォームを作った場合SelectFieldを動的に使いたいことがある。

データ

<option></option>を動的に作る方法。

htmlで記述した場合
<select id="users">
    <options value="1">日本 太郎</option>
    <options value="2">山田 太郎</option>
    <options value="3">山田 花子</option>
</select>
jinjaでの記述した場合
<form method="post>
    {{ form.csrf_token }}
    {{ form.name(id='users') }}
    {{ form.submit }}
</form>
forms.py
class UserForm(Form):
    name = SelectField('ユーザ名', coerce=int) # coerceにはstrで文字列でも値を格納できる。
    submit = SubmitField('登録')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._set_users()

    def _set_users(self):
        users = Users.query.all()
        # DBから取得したデータをchoiesにタプルで (valueの値, textの値) と格納するだけ。 
        self.users.choices = [(user.id, user.name) for user in users]

属性

動的に作られた<option></option>に属性を追加する方法。
これが意外と苦戦したところ。

widgets.py
from wtforms.widgets.core import HTMLString, html_params, Markup, escape, text_type

class MySelect(object):
    def __init__(self, multiple=False):
        self.multiple = multiple
        
    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)]

        # 選択できない初期値を追加する
        html.append(self.render_option(value='', label='選択してください', selected=False, disabled=True))

        for val, label, selected in field.iter_choices():
            # 各<option></option>にstyleを適用させることが可能に。
            html.append(self.render_option(val, label, selected, disabled=False, style='background-color:black'))
        html.append('</select>')
        return Markup(''.join(html))

    @classmethod
    def render_option(cls, value, label, selected, disabled, **kwargs):
        if value is True:
            # Handle the special case of a 'True' value.
            value = text_type(value)
        options = dict(kwargs, value=value)
        if selected:
            options['selected'] = True

        # hiddenをここで追加。
        if disabled:
            options['hidden'] = True

        return Markup('<option %s>%s</option>' % (html_params(**options), escape(label)))

forms.py
from widgets.py import MySelect

class Color(Form):
    name = SelectField('ユーザ名', coerce=int, widget=MySelect()) # widgetを指定するだけ。
    submit = SubmitField('登録')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._set_users()

    def _set_users(self):
        users = Users.query.all()
        self.users.choices = [(user.id, user.name) for user in users]
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?