Flask-WTF - validate_on_submit() is never executed
Solution 1
You're not inserting the CSRF field in the HTML form.
<form method=post>
{{ form.csrf_token }}
{{ form.name }}
<input type=submit>
</form>
After adding form.csrf_token
to the template (docs), the form will validate as expected.
Add print(form.errors)
after validating the form to see the errors that were raised. errors
will be empty before validation. In this case, there is an error about missing
@book.route('/book/new_no_csrf', methods=['GET', 'POST'])
def customers_new_no_csrf():
form = BookNewForm()
print(form.errors)
if form.is_submitted():
print("submitted")
if form.validate():
print("valid")
print(form.errors)
if form.validate_on_submit():
flash("Successfully created a new book")
return redirect(url_for('.books_show'))
return render_template('books_new.html', form=form)
{}
submitted
{'csrf_token': [u'CSRF token missing']}
127.0.0.1 - - [29/May/2012 02:01:08] "POST /book/new_no_csrf HTTP/1.1" 200 -
127.0.0.1 - - [29/May/2012 02:01:08] "GET /favicon.ico HTTP/1.1" 404 -
I created an example on GitHub.
Solution 2
you can print errors
print form.errors
or
app.logger.debug(form.errors)
and if you got csrf-error, you should set form.csrf_token in your template.
Solution 3
I came across this when trying to render a FormField
being iterated over my FieldList
in my template. I had to embed two hidden_tag elements one for the FieldList
form and one for the FieldForm
form, search the template comments for keyword "HIDDEN TAG"
class ParamRangeForm( FlaskForm ):
minX = FloatField( )
maxX = FloatField( )
class ParamRangesForm( FlaskForm ):
paramRanges = FieldList( FormField( ParamRangeForm ) )
submit = SubmitField( 'Submit' )
def loadParams( self ) :
for paramName in ["p1" , "p2" , "p3", "p4"] :
prf = ParamRangeForm( )
prf.minX = -100.9#float('-inf')
prf.maxX = 100.5#float('-inf')
self.paramRanges.append_entry( prf )
...
<form action="" method="POST" enctype="multipart/form-data">
{{ rangesForm.hidden_tag() }} <!--#### HIDDEN TAG #1 -->
<table>
<!--Print Column Headers-->
<thead>
<tr>
<th class="ColumnHeader">Parameter</td>
<th class="ColumnHeader">Min</td>
<th class="ColumnHeader">Max</td>
</tr>
</thead>
<!--Print Parameter Rows-->
<tbody>
{% for paramRange in rangesForm.paramRanges %}
<tr>
{{ paramRange.hidden_tag() }} <!--#### HIDDEN TAG #2 -->
<td>p{{ loop.index }}</td>
<td>{{ paramRange.minX }}</td>
<td>{{ paramRange.maxX }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{{ rangesForm.submit() }}
</form>
Solution 4
insert this after the tag in template html file:
{{ form.csrf_token }}
Solution 5
I was clearing the flask session if I wasn't logged in before every request. This was causing this issue.
@main.before_request
def before_request():
if not current_user.is_authenticated():
# TODO clean sessions may cause CSRF missing issue
session.clear()
print "Session Cleared"
return redirect(url_for('auth.login'))
kadrian
Full-stack web-hipster, UX lover, looking for machine learning, optimization and UI design. Useful stuff. Tokyo. Berlin.
Updated on July 09, 2022Comments
-
kadrian almost 2 years
I'm using Flask-WTF:
Here is my form:
from flask.ext.wtf import Form, TextField class BookNewForm(Form): name = TextField('Name')
Here is the controller:
@book.route('/book/new', methods=['GET', 'POST']) def customers_new(): form = BookNewForm() if form.is_submitted(): print "submitted" if form.validate(): print "valid" if form.validate_on_submit(): flash("Successfully created a new book") return redirect(url_for('.books_show')) return render_template('views/books_new.html', form=form)
Now the problem is, if you look at my print statements, it always prints submitted, but it NEVER prints valid and validate_on_submit() is never executed. Why?
-
Viraj Wadate over 5 yearsLink for WTF validate. Compare two dates if start date is greater than end date then give error. stackoverflow.com/a/53804438/9477847
-
-
kadrian almost 12 yearsthanks for this hint, but 'print form.errors' prints {} . Still form.validate() returns False
-
kadrian almost 12 yearsThank you so much! This was the exact problem! I didn't include the csrf field in my form. Trying to solve it with
{{ form.csrf }}
didn't work, but doing:{{ form.hidden_tag() }}
solved the problem! You were also right about the error printing, good to know how that works properly now! -
A.Ford almost 12 yearsGlad to help. If you're running WTForms 0.6 or later,
form.csrf
becameform.csrf_token
so watch out for that, butform.hidden_tag()
works just as well. -
skjoshi about 9 yearsThis was giving me nightmare. Thanks a lot.
-
roymustang86 about 7 yearsWonder why this critical part is missing from the docs. Thanks!
-
jxramos almost 7 yearsI was wondering how one would go about debugging Flask form validation problems. Very good