Flask WTForms BooleanField UnboundField

风格不统一 提交于 2021-02-11 12:32:22

问题


I am writing a script that normally retrieves 5 lines from the database and I want to display it as a checkbox list.

But it doesn't display correctly: it says " UnboundField "

form.py

class ExampleForm(FlaskForm):
    [...query & results...]
    for line in results_sql:
        list_checkbox[line.label] = BooleanField(line.label)

routes.py

@bp.route('/example')
def example():
    form = ExampleForm()
    return render_template("index.html", form=form)

index.html

<table class="table table-bordered table-condensed">
    {% for checkbox in form.list_checkbox %}
    <tr>
        <td>{{ checkbox }}</td>
        <td>{{ form.list_checkbox[checkbox ] }}</td>
    </tr>
    {% endfor %}
</table>

Result:


回答1:


You've put your fields inside a nested dictionary. The form can't bind such fields as it can't handle arbitrary containers.

Instead, you need to put the fields in a field enclosure. I'd use a FormField() field to point to a nested Form class. You can generate the nested Form class by calling the BaseForm() constructor:

What BaseForm provides is a container for a collection of fields, which it will bind at instantiation, and hold in an internal dict. Dict-style access on a BaseForm instance will allow you to access (and modify) the enclosed fields.

Then, when you create an instance of your ExampleForm() class, it'll bind the FormField field, which then in turn creates an instance of the nested form object, which then binds each of the fields you gave BaseForm()

Because calling BaseForm(fields) will create a form instance, you do need to wrap that in a function first before you can use it as a nested form:

def form_from_fields(fields):
    def create_form(prefix='', **kwargs):
        form = BaseForm(fields, prefix=prefix, meta=FlaskForm.Meta)
        form.process(**kwargs)
        return form
    return create_form

class ExampleForm(FlaskForm):
    # ...

    list_checkbox = FormField(
        form_from_fields(
            [(line.label, BooleanField(line.label)) for line in results_sql]
        )
    )

BaseForm() doesn't take any data like a Form class would, so you need to pass the parameters that FormField() passes into create an instance to the .process() method before returning the instance.

When iterating over the list_checkbox field when rendering, you get the fields directly and you get the label from the field object:

<table class="table table-bordered table-condensed">
    {% for checkbox in form.list_checkbox %}
    <tr>
        <td>{{ checkbox.label }}</td>
        <td>{{ checkbox }}</td>
    </tr>
    {% endfor %}
</table>

Demo (using the base WTForms library, but the Flask-WTF process is the same):

>>> from wtforms.form import BaseForm, Form
>>> from wtforms.fields import BooleanField, FormField
>>> fields = ['Calendrier', 'Commentaire', 'Dessin', 'Ex-libris', 'Gravure']
>>> def form_from_fields(fields):
...     def create_form(prefix='', **kwargs):
...         form = BaseForm(fields, prefix=prefix)
...         form.process(**kwargs)
...         return form
...     return create_form
...
>>> class ExampleForm(Form):
...     list_checkbox = FormField(form_from_fields([(field, BooleanField(field)) for field in fields]))
...
>>> form = ExampleForm()
>>> form.list_checkbox
<wtforms.fields.core.FormField object at 0x1232a76d8>
>>> list(form.list_checkbox)
[<wtforms.fields.core.BooleanField object at 0x1232a77f0>, <wtforms.fields.core.BooleanField object at 0x1232a78d0>, <wtforms.fields.core.BooleanField object at 0x1232a7978>, <wtforms.fields.core.BooleanField object at 0x1232a7a20>, <wtforms.fields.core.BooleanField object at 0x1232a7ac8>]
>>> print(*form.list_checkbox, sep='\n')
<input id="list_checkbox-Calendrier" name="list_checkbox-Calendrier" type="checkbox" value="y">
<input id="list_checkbox-Commentaire" name="list_checkbox-Commentaire" type="checkbox" value="y">
<input id="list_checkbox-Dessin" name="list_checkbox-Dessin" type="checkbox" value="y">
<input id="list_checkbox-Ex-libris" name="list_checkbox-Ex-libris" type="checkbox" value="y">
<input id="list_checkbox-Gravure" name="list_checkbox-Gravure" type="checkbox" value="y">

The FormField() field then also makes sure that you can set default values for your form, or that you can then access the data set when the form is posted again:

>>> form = ExampleForm(list_checkbox={'Calendrier': True})
>>> print(form.list_checkbox['Calendrier'])
<input checked id="list_checkbox-Calendrier" name="list_checkbox-Calendrier" type="checkbox" value="y">
>>> print(form.list_checkbox['Commentaire'])
<input id="list_checkbox-Commentaire" name="list_checkbox-Commentaire" type="checkbox" value="y">


来源:https://stackoverflow.com/questions/53340806/flask-wtforms-booleanfield-unboundfield

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!