Question

Using WTForms, I ask the user to enter two numbers that will be further used on a simple calculation. Those numbers both need to be validated.

I have defined the following form

class AForm(Form):
    ff=DecimalField(default=0.0, validators=[NumberRange(min=0, max=2)])

The template

<form action="/test" method=post>
    {% for L in entries %}
        {{ render_field(form.ff) }}
    {% endfor %}
    <input class="button" type="submit" value="calc">
</form>

The Flask view

@app.route('/test', methods=['GET', 'POST'])
def get_form():
    entries=[0, 1]
    form = AForm(request.form)
    ff_l=request.form.getlist('ff')
    if request.method == 'POST' and form.validate():
        L=0
        v=0
        a=0
        b=0
        for L,v in enumerate(ff_l):
            a=float(v)
            b+=a
        return render_template('res.html', b=b)
    return render_template('test.html', entries=entries, form=form)

I am aware I am using the getlist method, which is not part of WTForms, but this is the only solution found so far, since, by doing ff_l=form.ff.data, I would get a dict with only one value per field and not the whole list, associated to the given field.

Problems start when I want to validate submitted values: the form.validate() method will only validate the first value of the list, while the second will not be subjected to any validation.

My question: how is it possible to validate each value of a list ?

Thanks in advance !

Was it helpful?

Solution

You will want to use FieldList to let WTForms know there can be more than one entry:

field = DecimalField(default=0.0, validators=[NumberRange(min=0, max=2)])

class AForm(Form):
    ff = FieldList(field)

Then you should be able to simply set the data in the form constructor:

@app.route('/test', methods=['GET', 'POST'])
def get_form():
    entries=[0, 1]
    form = AForm(request.form, ff=entries)
    ff_l = form.ff.data
    if request.method == 'POST' and form.validate():
        result = sum(ff_l)
        return render_template('res.html', b=result)
    return render_template('test.html', form=form)

And your template should now loop over the subfields in form.ff:

<form action="/test" method=post>
    {% for field in form.ff %}
        {{ render_field(field) }}
    {% endfor %}
    <input class="button" type="submit" value="calc">
</form>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top