flask form.validate_on_submit() fails using wtforms
cherrypy, flask, python, wtforms
Solution
You call `form.validate()` everytime someone visits `'/'`. When the request is a GET, there is no form data causing validation to fail. You only want to try to validate the form when the request is a POST.
One way to do that is to check the request's method.
if request.method == 'POST':
if form.validate():
session['dataserver'] = ds = form.dataserver.data
return redirect(url_for('login'))
else:
flash('Failed validation')
Another common way to do this is with `validate_on_submit`. It handles checking for POSTs as well as validating the form.
if form.validate_on_submit():
session['dataserver'] = ds = form.dataserver.data
return redirect(url_for('login'))
Here you'd lose your ability to flash your `'validation failed'` message. That may be acceptable, though, because you can check for form errors in your template.
{% if form.errors %}
failed validation
{% endif %}
UPDATE
If you want to see the errors (which you may not), you can print them in the template instead of the generic "failed validation" message.
{% if form.errors %}
{{ form.errors }}
{% endif %}
Problem
Using @dirn's suggestions, the validation error does not display anymore, but it still seems to fail as neither the print statement in the root() function displays/runs nor does the new form.errors show. App Code: ``` #!/usr/bin/env python import cherrypy import os from flask import Flask, render_template, redirect, url_for, session, request, flash, abort, Markup from flask.ext.bootstrap import Bootstrap from sybload import funcs, forms app = Flask(__name__) app.debug = True app.config['SECRET_KEY'] = os.urandom(24) app.config['CSRF_ENABLED'] = True bootstrap = Bootstrap(app) dataserver_info = funcs.get_dataserver_info() dataservers = funcs.get_dataservers(dataserver_info) @app.route('/', methods=['GET', 'POST']) def root(): session.clear() form = forms.DataServersForm() form.dataserver.choices = zip(dataservers, dataservers) if form.validate_on_submit(): session['dataserver'] = form.dataserver.data # print statement below never runs print session['dataserver'], form.dataserver.data return redirect(url_for('login')) return render_template('root.html', title='Sybase Load App', form=form) def run_server(): cherrypy.tree.graft(app, '/') cherrypy.config.update({ 'log.access_file': 'logs/access.log', 'log.error_file': 'logs/errors.log', 'engine.autoreload_on': True, 'log.screen': True, 'server.socket_host': '0.0.0.0', 'server.socket_port': 5000, 'tools.sessions.on': True, 'tools.sessions.secure': True, 'tools.sessions.httponly': True }) cherrypy.engine.start() cherrypy.engine.block() if __name__ == '__main__': run_server() ``` Template (jinja2): ``` {% block body %} <form method='post' action='{{ url_for('login') }}'> {{ form.hidden_tag() }} {{ form.dataserver.label }}<br> {{ form.dataserver }}<br><br> {{ form.submit }} </form> <!-- Below never displays --> {% if form.errors %} failed validation {% endif %} {% endblock %} ``` Form: ``` from flask.ext.wtf import Form from wtforms import StringField, PasswordField, SelectField, SelectMultipleField, SubmitField, BooleanField from wtforms.validators import Required import funcs class DataServersForm(Form): dataserver = SelectField('Dataservers', validators=[Required()]) submit = SubmitField('Submit') ```