Handling Forms with Flask-WTF
While you can process form data directly from Flask's request object, the standard and more secure way is to use the Flask-WTF extension. This library provides a powerful way to create, validate, and secure your web forms.
Installation
First, add Flask-WTF to your project.
pip install Flask-WTF
Setting a Secret Key
Flask-WTF requires a "secret key" to protect your forms against Cross-Site Request Forgery (CSRF) attacks. This is a critical security feature. In your main application file, you need to set this key in the Flask app's configuration.
from flask import Flask
app = Flask(__name__)
# IMPORTANT: This key should be a random, complex string and
# should NOT be hardcoded in production. It's better to load it
# from an environment variable.
app.config['SECRET_KEY'] = 'a-very-secret-key'
Creating a Form
With Flask-WTF, you define your forms as classes. Each field in the form is an object with built-in validation rules.
Let's create a simple contact form.
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Email
class ContactForm(FlaskForm):
name = StringField('Name', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
message = TextAreaField('Message', validators=[DataRequired()])
submit = SubmitField('Submit')
Here, DataRequired ensures the field is not empty, and Email validates that the input has a valid email format.
Handling the Form in a Route
Now, you can use this form class in your route. The form.validate_on_submit() method is a convenient helper that checks if the form was submitted (i.e., it was a POST request) and if all the data is valid according to your validators.
from flask import render_template, flash
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm()
if form.validate_on_submit():
# Here you would process the data, e.g., send an email
# or save it to a database.
name = form.name.data
email = form.email.data
message = form.message.data
flash(f'Thanks for your message, {name}!')
return redirect(url_for('contact'))
return render_template('contact.html', form=form)
The flash() function is a simple way to show a one-time message to the user after they are redirected.
Rendering the Form in a Template
Finally, you can render this form in your Jinja template. Flask-WTF makes this very easy. The form.hidden_tag() is essential, as it includes the CSRF protection token.
templates/contact.html
{% extends "base.html" %}
{% block content %}
<h1>Contact Us</h1>
<form method="POST" action="">
{{ form.hidden_tag() }}
<p>
{{ form.name.label }}<br>
{{ form.name(size=32) }}
</p>
<p>
{{ form.email.label }}<br>
{{ form.email(size=32) }}
</p>
<p>
{{ form.message.label }}<br>
{{ form.message(rows=5, cols=35) }}
</p>
<p>{{ form.submit() }}</p>
</form>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% endblock %}
Using Flask-WTF not only simplifies form processing but also makes your application significantly more secure.