Reputation: 65
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?
Upvotes: 2
Views: 2118
Reputation: 898
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.
Upvotes: 2