Day 45: Flask — Forms and Validation
Flask Forms Unleashed: Ensuring Data Integrity through Validation
Author: Harshil Chovatiya

Overview
Welcome to Day 45 of our Python and web development series! Today, we’ll explore an essential aspect of web development: handling forms and validating input in Flask. Forms are a fundamental component of web applications, allowing users to interact with your application by submitting data. Properly handling and validating this input is crucial for maintaining data integrity and security.
In this blog, we will cover:
- Introduction to Flask-WTF
- Creating Forms with Flask-WTF
- Validating Form Data
- Handling Form Submissions
- Displaying Form Errors
- Best Practices for Form Handling
Let’s dive into these topics to understand how to create robust forms and validate user input effectively in Flask.
Introduction to Flask-WTF
Flask-WTF is an extension for Flask that integrates WTForms with Flask. It simplifies form handling by providing a more Pythonic approach to form creation and validation. WTForms is a library that helps you define forms with field types, validation rules, and more.
Features of Flask-WTF:
- Form Handling: Easily define and manage forms.
- Validation: Built-in validators for common data validation needs.
- CSRF Protection: Automatically adds CSRF tokens to forms for security.
- Customizable: Allows for custom validation and error handling.
Installing Flask-WTF
To get started with Flask-WTF, you need to install it along with Flask:
pip install flask-wtf
Creating Forms with Flask-WTF
With Flask-WTF, you define forms as Python classes. Each class represents a form and its fields. Let’s create a simple contact form to illustrate this.
Setting Up the Project
- Project Structure:
mkdir flask_forms
cd flask_forms
- Set Up Virtual Environment and Install Dependencies:
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install Flask Flask-WTF
- Create the Flask Application:
Create a file named app.py
:
# app.py
from flask import Flask, render_template, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Length
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
class ContactForm(FlaskForm):
name = StringField('Name', validators=[DataRequired(), Length(min=2, max=50)])
email = StringField('Email', validators=[DataRequired()])
message = TextAreaField('Message', validators=[DataRequired(), Length(min=10, max=500)])
submit = SubmitField('Send')
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm()
if form.validate_on_submit():
# Process the form data here
return redirect(url_for('success'))
return render_template('contact.html', form=form)
@app.route('/success')
def success():
return "Form submitted successfully!"
if __name__ == '__main__':
app.run(debug=True)
- Create the
templates
Directory andcontact.html
Template:
Inside the flask_forms
directory, create a folder named templates
and add contact.html
:
<!-- templates/contact.html -->
<!DOCTYPE html>
<html>
<head>
<title>Contact Us</title>
</head>
<body>
<h1>Contact Us</h1>
<form method="POST" action="{{ url_for('contact') }}">
{{ form.hidden_tag() }}
<p>
{{ form.name.label }}<br>
{{ form.name(size=32) }}<br>
{% for error in form.name.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</p>
<p>
{{ form.email.label }}<br>
{{ form.email(size=32) }}<br>
{% for error in form.email.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</p>
<p>
{{ form.message.label }}<br>
{{ form.message(rows=5, cols=40) }}<br>
{% for error in form.message.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</p>
<p>{{ form.submit() }}</p>
</form>
</body>
</html>

Explanation:
ContactForm
Class: Defines the form fields and validation rules.form.validate_on_submit()
: Validates the form data when submitted.{{ form.hidden_tag() }}
: Adds a CSRF token to the form.{% for error in form.field.errors %}
: Displays validation errors for each field.
Validating Form Data
Validation ensures that the data submitted through forms is correct and secure. Flask-WTF provides several built-in validators, but you can also create custom validators.
Built-in Validators
DataRequired()
: Ensures that the field is not empty.Length(min, max)
: Validates the length of the input.Email()
: Validates that the input is a valid email address.
Creating Custom Validators
Custom validators allow you to define complex validation logic. Here’s how to create and use a custom validator:
- Define a Custom Validator:
# app.py
from wtforms import ValidationError
def validate_email_domain(form, field):
if not field.data.endswith('@example.com'):
raise ValidationError('Email must be from the domain @example.com')
- Apply the Custom Validator to a Field:
# app.py
class ContactForm(FlaskForm):
# other fields
email = StringField('Email', validators=[DataRequired(), validate_email_domain])
Explanation:
validate_email_domain
Function: Checks if the email ends with@example.com
.ValidationError
: Raised if validation fails.
Handling Form Submissions
Handling form submissions involves processing the data and performing actions like saving to a database, sending emails, or redirecting users.
Example: Processing Form Data
Update the contact
route in app.py
to handle form submissions:
# app.py
from flask import Flask, render_template, redirect, url_for, flash
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm()
if form.validate_on_submit():
name = form.name.data
email = form.email.data
message = form.message.data
# Here you can add code to process the form data (e.g., save to database, send email)
flash(f'Thank you {name}, your message has been sent!')
return redirect(url_for('success'))
return render_template('contact.html', form=form)
Explanation:
flash
Function: Used to display a message to the user after form submission.- Processing Form Data: Handle the form data according to your application’s requirements.
Displaying Form Errors
Displaying form errors helps users correct their input. Flask-WTF makes it easy to show validation errors next to form fields.
Example: Displaying Errors in the Template
Update the contact.html
template to show errors for each field:
<!-- templates/contact.html -->
<!-- Inside <form> tag -->
{% for field in form %}
<p>
{{ field.label }}<br>
{{ field(size=32) }}<br>
{% for error in field.errors %}
<span style="color: red;">[{{ error }}]</span><br>
{% endfor %}
</p>
{% endfor %}
Explanation:
{{ field.errors }}
: Displays validation errors associated with each field.

Best Practices for Form Handling
- Sanitize and Validate Input: Always validate and sanitize user input to prevent security vulnerabilities such as SQL injection or cross-site scripting (XSS).
- Provide Clear Error Messages: Ensure that error messages are clear and helpful, guiding users to correct their input.
- Use CSRF Protection: Flask-WTF automatically adds CSRF protection to forms, preventing cross-site request forgery attacks.
- Handle Form Submission Gracefully: Provide feedback to users after form submission, whether successful or with errors.
- Organize Forms: Keep your forms organized in separate files or modules if your application grows larger. This approach improves maintainability and readability.
Conclusion
On Day 45, we explored handling forms and validating input in Flask using Flask-WTF. We learned how to create and manage forms, apply built-in and custom validators, and handle form submissions effectively. Proper form handling and validation are crucial for building secure and user-friendly web applications.
By integrating these techniques into your Flask projects, you’ll ensure that user data is handled correctly and that your web applications provide a smooth and reliable user experience.
Thank you for following along with Day 45 of our Python and web development series.
Happy coding!