I
I
Igor Che2016-10-14 12:06:20
Flask
Igor Che, 2016-10-14 12:06:20

How to display checkbox list in WTForms?

WTForms does not have a chexbox out of the box.
Found a way to display them here .
I do this:
forms.py:

class MultiCheckboxField(SelectMultipleField):
  widget = widgets.ListWidget(prefix_label=False)
  option_widget = widgets.CheckboxInput()

class BrifStoreForm(Form):
choices = [(1, 'one'),
           (2, 'two'),
           (3, 'tree')]
resident = MultiCheckboxField('Label',
                              choices=choices, 
                              coerce=int)


app.py:
from flask import Flask, render_template, request
from forms import BrifStoreForm

app = Flask(__name__)
app.config.from_object('config')

@app.route('/', methods=['GET', 'POST'])
def brif_store():
  form = BrifStoreForm()
  if request.method == 'GET':
    return render_template('brif-store.html',
                           form=form)
  elif request.method == 'POST' and form.validate_on_submit():
    return render_template('result-form.html',
                           form=form)
  return render_template('brif-store.html',
                         form=form)

if __name__ == '__main__':
  app.run()


result-form.html:
{% if form.resident.data %}
        {{ form.resident.data }}
    {% endif %}

And everything turns out, checkboxes are displayed as desired. Next, I pass the results of the form to the jinja2 template, but instead of the selected values, I get the keys, in this form [1, 2]. How to display the values ​​of selected checkboxes?
As I understand it, you need to override the parent class SelectMultipleFields. There he is:
class SelectMultipleField(SelectField):
    """
    No different from a normal select field, except this one can take (and
    validate) multiple choices.  You'll need to specify the HTML `size`
    attribute to the select field when rendering.
    """
    widget = widgets.Select(multiple=True)

    def iter_choices(self):
        for value, label in self.choices:
            selected = self.data is not None and self.coerce(value) in self.data
            yield (value, label, selected)

    def process_data(self, value):
        try:
            self.data = list(self.coerce(v) for v in value)
        except (ValueError, TypeError):
            self.data = None

    def process_formdata(self, valuelist):
        try:
            self.data = list(self.coerce(x) for x in valuelist)
        except ValueError:
            raise ValueError(self.gettext('Invalid choice(s): one or more data inputs could not be coerced'))

    def pre_validate(self, form):
        if self.data:
            values = list(c[0] for c in self.choices)
            for d in self.data:
                if d not in values:
                    raise ValueError(self.gettext("'%(value)s' is not a valid choice for this field") % dict(value=d))

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
Igor Che, 2016-10-16
@chewarer

I decided.
The template with the results of filling out the form did this:

<ul>
    {% for field in form if field.widget.input_type != 'hidden' %}
        {% if field.data %}
            <li>
                {{ field.label }}<br>
                {% if field.type == 'MultiCheckboxField' %}
                    {% for opt in field.data %}
                        {{ dict(field.choices)[opt] }}<br>
                    {% endfor %}
                {% elif field.type == 'RadioField' %}
                    {{ dict(field.choices)[field.data] }}<br>
                {% else %}
                    {{ field.data }}
                {% endif %}
            </li>
        {% endif %}
    {% endfor %}
</ul>

But I myself do not like this solution because I have to collective farm in the template.
In general, it is surprising that on the Internet I did not find at all that someone wondered how to display the value, and not the key of the selected RadioField or CheckboxField.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question