2

I am giving my first go at bringing up a small website with flask, bootstrap, and wtforms. I am running into an issue where my wtforms fields are not sending values when submitted. I have a very basic wtform defined as follows:

class GeneralForm(Form):
    boolean_val = BooleanField('Boolean')
    a_float = FloatField('Severity')
    submit = SubmitField('Submit')

I also have an html template which I render the form in:

{% block content %}
    <div class="col-md-12">
        {{form|render_form()}}
    </div>
{%- endblock %}

Everything renders fine. When the form is submitted, I check it like so:

@app.route('/form', methods=['GET', 'POST'])
def do_form():
    general_form = GeneralForm()

    if general_form.validate_on_submit():
        return "Value {}".format(general_form.boolean_val.data)

    return render_template('symptomsform.html', form=general_form)

What I find is that the value for the boolean field is always the default value (false). I also notice that only a default value is provided when I check the float field. I checked the html for the page, I found that the input fields looked like:

<label for="boolean_val">
  <input type="checkbox">Boolean
</label>

What stood out to me is the input field was missing a name in its tag. So, I manually stuck the name in and my test app was receiving the actual value of the checkbox.

My question is: what am I doing wrong with creating the input fields such that the values of the fields are not being sent with the form submission? I suspect the input fields should have names. So, why are names not being generated on the input fields?

2
  • Use Following Jinja syntax in your HTML Template <p> {{ form.boolean_val.label }} {{ form.boolean_val }} </p> Commented Mar 16, 2018 at 8:34
  • @GeekSambhu I tried your suggestion and that caused the input field to be generated with a name. While that fixes the issue, this is not a convenient way of generating a large number of fields. I have updated my question to include my html template in case that identifies anything I did wrong. Commented Mar 16, 2018 at 8:55

1 Answer 1

2

Below is a sample script with the fixes,

app.py

from flask import Flask, render_template
from flask_wtf import Form
from wtforms import SubmitField, BooleanField, FloatField
from flask import request
from jinja2 import filters


app = Flask(__name__)
app.config['SECRET_KEY'] = 'catchmeifyoucan'

class GeneralForm(Form):
    boolean_val = BooleanField('Boolean')
    a_float = FloatField('Severity')
    submit = SubmitField('Submit')


@app.route('/wtforms', methods=['GET', 'POST'])
def debug_wtforms():
    form = GeneralForm()
    if request.method == 'POST' and form.validate_on_submit():
        print(form.boolean_val.data)
        print(form.a_float.data)
    return render_template('index.html', form=form)


# This is a jinja2 custom filter for rendering a form
@app.template_filter()
def render_form(form, action='/', method='post'):
    temp = ''
    start_form = "<form action=" + action + " method=" + method + ">"
    end_form = "</form>"
    temp += start_form
    for el in form:
        temp += str(el())
    temp += end_form
    return filters.do_mark_safe(temp)


if __name__ == "__main__":
    app.run(debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wtforms debug</title>
</head>
<body>
{{ form | render_form(action=url_for('debug_wtforms')) }}
</body>
</html>

The custom jinja2 filter given below helps you to render the form with the name attribute,

# This is a jinja2 custom filter for rendering a form
@app.template_filter()
def render_form(form, action='/', method='post'):
    temp = ''
    start_form = "<form action=" + action + " method=" + method + ">"
    end_form = "</form>"
    temp += start_form
    for el in form:
        temp += str(el())
    temp += end_form
    return filters.do_mark_safe(temp)

This filter has two default arguments, action and method which could be passed if you want to modify the form method and action.

The current filter won't display the form field label, but if you want to display form field label, you can access it using str(el.label()) and append it to the temp variable in the custom filter.

Note : You can make necessary tweaks to the custom filter to modify how the form must be displayed

I hope this helps.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for this. However, I have to ask: is it expected that a custom filter must be used to get wtforms fields to render in a way that makes the field work correctly? I would think the default render_form() should do this for you.
@ratnapper np :) Glad it helped you. But can you point me to the documentation of the default render_form(), since I am in the clouds here.
I was following the example app here: github.com/mbr/flask-bootstrap/tree/master/sample_app. On second look, I see that they actually do have their own implementation of render_form. I realize I missed this previously, doh! I guess there is still some "default" render_form() that I was using since my form was still rendering, but not as I expected.
I haven't seen any render_form filter in the official documentation so far. That's why was confused. Good to know you figured it out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.