This blog teaches you how to handle user input and forms in Flask using Flask-WTF, a Flask extension for working with web forms. You will learn how to create, render, validate, process, protect, and customize your forms in your web application.
1. Introduction
In this tutorial, you will learn how to handle user input and forms in Flask using Flask-WTF, a Flask extension for working with web forms. Web forms are essential for any web application that needs to collect data from users, such as registration, login, contact, feedback, or survey forms. However, working with forms can be challenging, as you need to deal with various issues such as:
- Creating HTML forms with the correct input fields and attributes
- Rendering the forms in your templates with the appropriate styling and layout
- Validating the user input and displaying error messages
- Processing the form data and performing the desired actions
- Adding security features such as CSRF protection to prevent malicious attacks
- Customizing the forms with different templates and widgets to enhance the user experience
Flask-WTF simplifies these tasks by providing a convenient wrapper around the WTForms library, which is a popular Python library for form validation and rendering. Flask-WTF also integrates with Flask’s template engine, Jinja2, to make it easy to render your forms in your HTML templates. Additionally, Flask-WTF offers some useful features such as:
- Generating CSRF tokens and validating them automatically
- Supporting file uploads and multiple forms on the same page
- Providing a variety of field types and widgets, such as date pickers, file inputs, and select fields
- Allowing you to create custom validators and widgets for your forms
By the end of this tutorial, you will be able to create and render forms in Flask using Flask-WTF, validate and process the user input, add CSRF protection to your forms, and customize your forms with templates and widgets. You will also build a simple web application that demonstrates how to use Flask-WTF in practice.
To follow this tutorial, you will need:
- A basic understanding of Python and Flask
- A working Flask development environment
- A text editor or IDE of your choice
- A web browser to test your application
Are you ready to start working with forms in Flask? Let’s begin!
2. Installing and Configuring Flask-WTF
Before you can use Flask-WTF in your Flask application, you need to install and configure it properly. In this section, you will learn how to do that in a few simple steps.
The first step is to install Flask-WTF using pip, a Python package manager. You can do this by running the following command in your terminal:
pip install flask-wtf
This will download and install Flask-WTF and its dependencies, such as WTForms and its-blinker. You can check the installed version of Flask-WTF by running:
pip show flask-wtf
The second step is to import Flask-WTF in your Flask application. You can do this by adding the following line at the top of your app.py file:
from flask_wtf import FlaskForm
This will import the FlaskForm class, which is the base class for all your forms. You will use this class to create and define your forms later.
The third step is to configure Flask-WTF in your Flask application. You can do this by setting some configuration variables in your app.py file. The most important variable is the SECRET_KEY, which is used to generate and validate CSRF tokens. You can set this variable to any random string, but make sure it is secret and hard to guess. For example, you can use the following line to set the SECRET_KEY:
app.config['SECRET_KEY'] = 'a very secret key'
Another configuration variable that you can set is the WTF_CSRF_ENABLED, which determines whether CSRF protection is enabled or not. By default, this variable is set to True, which means that CSRF protection is enabled. However, if you want to disable CSRF protection for some reason, you can set this variable to False. For example, you can use the following line to disable CSRF protection:
app.config['WTF_CSRF_ENABLED'] = False
However, it is not recommended to disable CSRF protection, as it can expose your application to malicious attacks. Therefore, you should always keep CSRF protection enabled unless you have a good reason not to.
There are other configuration variables that you can set for Flask-WTF, such as the WTF_CSRF_TIME_LIMIT, which determines how long a CSRF token is valid, or the WTF_CSRF_CHECK_DEFAULT, which determines whether CSRF protection is applied to all views by default.
Once you have installed and configured Flask-WTF, you are ready to create and render your forms. How do you do that? You will learn in the next section.
3. Creating and Rendering Forms
Now that you have installed and configured Flask-WTF, you can start creating and rendering your forms. In this section, you will learn how to do that using the FlaskForm class and the render_template function.
The first step is to create a form class that inherits from the FlaskForm class. A form class is a Python class that defines the fields and validators of your form. Each field is an instance of a field class, such as StringField, IntegerField, BooleanField, etc. Each field class has some attributes and methods that control the behavior and appearance of the field, such as label, default, validators, widget, etc.
For example, suppose you want to create a simple contact form that asks for the user’s name, email, and message. You can create a form class like this:
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField
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()])
This form class has three fields: name, email, and message. Each field has a label that will be displayed in the HTML form, and a list of validators that will check the user input for errors. For example, the DataRequired validator will ensure that the field is not empty, and the Email validator will ensure that the field contains a valid email address.
The second step is to create an instance of your form class in your view function. A view function is a Python function that handles a request and returns a response. You can use the FlaskForm constructor to create a form instance and pass it the request.form object, which contains the data submitted by the user. For example, you can create a view function like this:
from flask import Flask, render_template, request
from forms import ContactForm
app = Flask(__name__)
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm(request.form)
# do something with the form data
return render_template('contact.html', form=form)
This view function handles the /contact route and accepts both GET and POST methods. It creates a form instance using the request.form object and passes it to the render_template function, which renders a template file called contact.html and returns the HTML response. You can find more information about the request object and the render_template function in the Flask documentation.
The third step is to render your form in your template file. A template file is an HTML file that contains placeholders for dynamic content, such as variables, expressions, loops, etc. You can use the Jinja2 template engine to render your template files and fill in the placeholders with the values passed from the view function. You can find more information about the Jinja2 template engine and its syntax in the Jinja2 documentation.
To render your form in your template file, you can use the form object and its attributes and methods. For example, you can use the form.hidden_tag() method to generate a hidden input field that contains the CSRF token, which is required for CSRF protection. You can also use the form.field_name.label and form.field_name methods to generate the label and the input field for each field in your form. You can also use the form.field_name.errors attribute to access the list of errors for each field, if any. For example, you can create a template file like this:
<html>
<head>
<title>Contact Form</title>
</head>
<body>
<h1>Contact Form</h1>
<form method="POST">
{{ form.hidden_tag() }}
<p>
{{ form.name.label }}<br>
{{ form.name }}<br>
{% for error in form.name.errors %}
<span style="color: red;">{{ error }}</span><br>
{% endfor %}
</p>
<p>
{{ form.email.label }}<br>
{{ form.email }}<br>
{% for error in form.email.errors %}
<span style="color: red;">{{ error }}</span><br>
{% endfor %}
</p>
<p>
{{ form.message.label }}<br>
{{ form.message }}<br>
{% for error in form.message.errors %}
<span style="color: red;">{{ error }}</span><br>
{% endfor %}
</p>
<p>
<input type="submit" value="Submit">
</p>
</form>
</body>
</html>
You can also use the form.field_name.widget.args and form.field_name.widget.kwargs attributes to access the arguments and keyword arguments passed to the field constructor, such as the default value, the placeholder, the class, etc. You can use these attributes to customize the appearance and behavior of your fields. For example, you can change the size of the message field by adding the following line to your form class:
message = TextAreaField('Message', validators=[DataRequired()], widget=TextArea(rows=10, cols=40))
This will create a text area field with 10 rows and 40 columns.
By following these steps, you can create and render any form in Flask using Flask-WTF. However, creating and rendering forms is not enough. You also need to validate and process the user input and perform the desired actions. How do you do that? You will learn in the next section.
4. Validating and Processing Form Data
Once you have created and rendered your forms, you need to validate and process the user input and perform the desired actions. In this section, you will learn how to do that using the form.validate_on_submit() method and the request object.
The first step is to check if the form is submitted and valid using the form.validate_on_submit() method. This method returns True if the form is submitted using a POST request and passes all the validators. Otherwise, it returns False. You can use this method to control the flow of your view function and decide what to do next. For example, you can use an if-else statement like this:
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm(request.form)
if form.validate_on_submit():
# do something with the valid form data
else:
# render the form with or without errors
This view function checks if the form is submitted and valid using the form.validate_on_submit() method. If it is, it executes the code inside the if block, which can be anything you want, such as sending an email, saving the data to a database, redirecting to another page, etc. If it is not, it executes the code inside the else block, which usually renders the form again with or without errors.
The second step is to access the form data and perform the desired actions using the request object. The request object is a global object that contains information about the current request, such as the method, the URL, the headers, the cookies, the files, etc. You can use the request object to access the form data and perform the desired actions. For example, you can use the request.form attribute to access the form data as a dictionary, and use the request.files attribute to access the uploaded files as a dictionary. You can also use the request.args attribute to access the query parameters as a dictionary, and use the request.json attribute to access the JSON data as a dictionary. You can find more information about the request object and its attributes in the Flask documentation.
For example, suppose you want to send an email to the user who submitted the contact form, using the name, email, and message fields. You can access the form data using the request.form attribute and use the smtplib module to send an email. You can also use the flash function to display a message to the user, and use the redirect function to redirect the user to another page. You can do something like this:
import smtplib
from flask import Flask, render_template, request, flash, redirect, url_for
from forms import ContactForm
app = Flask(__name__)
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm(request.form)
if form.validate_on_submit():
# access the form data
name = request.form['name']
email = request.form['email']
message = request.form['message']
# send an email to the user
sender = 'your_email@example.com'
password = 'your_password'
subject = 'Thank you for contacting us'
body = f'Hello {name},\n\nWe have received your message and we will get back to you soon.\n\nYour message:\n{message}\n\nBest regards,\nYour Team'
message = f'Subject: {subject}\n\n{body}'
server = smtplib.SMTP('smtp.example.com', 587)
server.starttls()
server.login(sender, password)
server.sendmail(sender, email, message)
server.quit()
# display a message to the user
flash('Your message has been sent. Thank you for contacting us.')
# redirect the user to another page
return redirect(url_for('index'))
else:
# render the form with or without errors
return render_template('contact.html', form=form)
This view function sends an email to the user using the smtplib module, displays a message to the user using the flash function, and redirects the user to the index page using the redirect and url_for functions. You can find more information about these functions in the Flask documentation.
By following these steps, you can validate and process any form data in Flask using Flask-WTF and the request object. However, validating and processing form data is not enough. You also need to add CSRF protection to your forms to prevent malicious attacks. How do you do that? You will learn in the next section.
5. Adding CSRF Protection to Your Forms
CSRF stands for Cross-Site Request Forgery, which is a type of web attack that exploits the trust between a user and a web application. In a CSRF attack, an attacker tricks a user into submitting a malicious request to a web application that the user is already authenticated with, such as changing their password, transferring money, or deleting their account. The web application cannot distinguish between a legitimate request and a forged request, and executes the request as if it came from the user.
To prevent CSRF attacks, you need to add CSRF protection to your forms. CSRF protection works by generating a random token for each form and storing it in a hidden input field and in a cookie. When the user submits the form, the web application compares the token from the input field and the token from the cookie, and only accepts the request if they match. This way, the web application can verify that the request came from the same origin as the form, and not from a malicious site.
Flask-WTF makes it easy to add CSRF protection to your forms, as it does most of the work for you. All you need to do is to follow these steps:
- Set a secret key for your Flask application using the app.config[‘SECRET_KEY’] variable, as explained in the previous section.
- Import the CSRFProtect class from the flask_wtf.csrf module and create an instance of it with your Flask application as an argument. For example, you can add the following lines to your app.py file:
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'a very secret key'
csrf = CSRFProtect(app)
- Use the form.hidden_tag() method in your template file to generate a hidden input field that contains the CSRF token. For example, you can add the following line to your contact.html file:
{{ form.hidden_tag() }}
- That’s it! Flask-WTF will automatically generate and validate the CSRF tokens for you, and reject any request that does not have a valid token. You can also customize the CSRF protection behavior by setting some configuration variables, such as the WTF_CSRF_TIME_LIMIT, which determines how long a CSRF token is valid, or the WTF_CSRF_HEADERS, which determines which headers are checked for the CSRF token.
By following these steps, you can add CSRF protection to your forms in Flask using Flask-WTF and prevent CSRF attacks. However, adding CSRF protection to your forms is not enough. You also need to customize your forms with templates and widgets to enhance the user experience. How do you do that? You will learn in the next section.
6. Customizing Your Forms with Templates and Widgets
In the previous sections, you learned how to create, render, validate, process, and protect your forms in Flask using Flask-WTF. However, you may not be satisfied with the default appearance and behavior of your forms, and you may want to customize them to suit your needs and preferences. In this section, you will learn how to do that using templates and widgets.
Templates are HTML files that contain placeholders for dynamic content, such as variables, expressions, loops, etc. You can use the Jinja2 template engine to render your templates and fill in the placeholders with the values passed from the view function. You can also use templates to customize the layout and style of your forms, such as adding headers, footers, navigation bars, buttons, etc. You can use HTML tags and attributes, CSS rules, and JavaScript code to achieve the desired effects. You can find more information about the Jinja2 template engine and its syntax in the Jinja2 documentation.
Widgets are Python classes that control how a field is rendered in HTML. Each field class has a widget attribute that determines which widget is used to render the field. For example, the StringField class uses the TextInput widget, which renders a text input field. The BooleanField class uses the CheckboxInput widget, which renders a checkbox. You can use the widget argument in the field constructor to specify a different widget for a field. For example, you can use the PasswordInput widget to render a password field. You can also create your own widgets by subclassing the Widget class and overriding the __call__ method.
For example, suppose you want to customize your contact form to make it more attractive and user-friendly. You can do something like this:
- Create a base.html template file that contains the common elements of your web pages, such as the header, the footer, the navigation bar, etc. You can use the {% block %} and {% endblock %} tags to define blocks that can be overridden by other templates. For example, you can create a base.html file like this:
<html>
<head>
<title>{{ title }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div id="header">
<h1>My Web Application</h1>
<ul id="nav">
<li><a href="{{ url_for('index') }}">Home</a></li>
<li><a href="{{ url_for('contact') }}">Contact</a></li>
</ul>
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="footer">
<p>© 2024 My Web Application. All rights reserved.</p>
</div>
</body>
</html>
- Create a contact.html template file that extends the base.html template file and overrides the content block. You can use the {% extends %} tag to inherit from another template, and use the form object and its attributes and methods to render your form. You can also use the {{ get_flashed_messages() }} function to display the messages flashed by the flash function. For example, you can create a contact.html file like this:
{% extends "base.html" %}
{% block content %}
<h2>Contact Us</h2>
<p>Please fill out the form below and we will get back to you soon.</p>
<form method="POST" id="contact-form">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.name.label }}<br>
{{ form.name(class="form-control") }}<br>
{% for error in form.name.errors %}
<span class="error">{{ error }}</span><br>
{% endfor %}
</div>
<div class="form-group">
{{ form.email.label }}<br>
{{ form.email(class="form-control") }}<br>
{% for error in form.email.errors %}
<span class="error">{{ error }}</span><br>
{% endfor %}
</div>
<div class="form-group">
{{ form.message.label }}<br>
{{ form.message(class="form-control") }}<br>
{% for error in form.message.errors %}
<span class="error">{{ error }}</span><br>
{% endfor %}
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary">
</div>
</form>
{% for message in get_flashed_messages() %}
<p class="message">{{ message }}</p>
{% endfor %}
{% endblock %}
- Create a style.css file that contains the CSS rules for your web pages. You can use the class and id selectors to target specific elements and apply the desired styles. For example, you can create a style.css file like this:
#header {
background-color: #333;
color: white;
padding: 20px;
}
#nav {
list-style: none;
margin: 0;
padding: 0;
}
#nav li {
display: inline-block;
margin-right: 10px;
}
#nav a {
color: white;
text-decoration: none;
}
#nav a:hover {
color: yellow;
}
#content {
margin: 20px;
}
#footer {
background-color: #333;
color: white;
padding: 10px;
text-align: center;
}
.form-group {
margin-bottom: 10px;
}
.form-control {
width: 300px;
}
.error {
color: red;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 5px;
}
.btn-primary {
background-color: blue;
color: white;
}
.message {
color: green;
}
- Use the widget argument in the field constructor to specify a different widget for a field. For example, you can use the PasswordInput widget to render a password field, and use the widget.args and widget.kwargs attributes to customize the widget. For example, you can add the following line to your form class:
password = StringField('Password', validators=[DataRequired()], widget=PasswordInput(placeholder='Enter your password'))
This will create a password field with a placeholder text that says ‘Enter your password’.
By following these steps, you can customize your forms with templates and widgets in Flask using Flask-WTF and Jinja2. However, customizing your forms is not enough. You also need to test and debug your forms to ensure that they work as expected. How do you do that? You will learn in the next section.
7. Conclusion
In this tutorial, you learned how to handle user input and forms in Flask using Flask-WTF, a Flask extension for working with web forms. You learned how to:
- Install and configure Flask-WTF in your Flask application
- Create and render forms using the FlaskForm class and the render_template function
- Validate and process form data using the form.validate_on_submit() method and the request object
- Add CSRF protection to your forms using the form.hidden_tag() method and the CSRFProtect class
- Customize your forms with templates and widgets using the Jinja2 template engine and the widget argument
By following these steps, you can create and handle any form in Flask using Flask-WTF, and make your web application more interactive and user-friendly. You can also use Flask-WTF to create more complex forms, such as forms with multiple pages, forms with file uploads, forms with dynamic fields, etc. You can find more examples and documentation on the Flask-WTF website.
We hope you enjoyed this tutorial and learned something new. If you have any questions or feedback, please feel free to leave a comment below. Thank you for reading and happy coding!