In web development, forms are a crucial way for users to interact with applications, such as user registration, login, and submitting comments. Although Flask doesn’t have built-in form handling functionality, we can easily implement form definition, validation, and submission using the Flask-WTF extension (based on the WTForms library). This article will guide you through the core knowledge of handling forms with WTForms in Flask, starting from the basics.
1. Install Dependencies¶
First, install the Flask-WTF extension (it integrates WTForms, so no separate installation is needed). Open your terminal and run:
pip install flask-wtf
2. Commonly Used WTForms Field Types¶
WTForms provides various predefined field types corresponding to different HTML input controls. Here are the most commonly used ones for beginners:
| WTForms Field | HTML Equivalent Type | Description |
|---|---|---|
StringField |
<input type="text"> |
Single-line text input (e.g., username, email) |
PasswordField |
<input type="password"> |
Password input (hides entered content) |
SubmitField |
<input type="submit"> |
Submit button |
IntegerField |
<input type="number"> |
Integer input |
BooleanField |
<input type="checkbox"> |
Checkbox (stores True/False values) |
RadioField |
<input type="radio"> |
Radio button group |
SelectField |
<select> |
Dropdown menu |
3. Defining a Form Class¶
In Flask, define forms by inheriting from the FlaskForm class and declaring specific fields within the class. For example, create a simple login form:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, Email # Import validators
class LoginForm(FlaskForm):
# Username: Label "Username", required (DataRequired), length 3-20 (Length)
username = StringField('用户名', validators=[
DataRequired(message='用户名不能为空'),
Length(min=3, max=20, message='用户名长度需3-20字符')
])
# Email: Label "邮箱", required and valid email format (Email)
email = StringField('邮箱', validators=[
DataRequired(message='邮箱不能为空'),
Email(message='请输入有效的邮箱地址')
])
# Password: Label "密码", required
password = PasswordField('密码', validators=[
DataRequired(message='密码不能为空')
])
# Submit button
submit = SubmitField('登录')
Key Points:
- FlaskForm is the base class provided by Flask-WTF; inherit it to create forms.
- The validators parameter defines field validation rules (e.g., required, length limits, format checks). DataRequired ensures the field is not empty, and Email validates email format.
- The field name (e.g., username) is a Python variable name, while the label string (e.g., ‘用户名’) is displayed in the template.
4. Handling Forms in View Functions¶
Forms require handling GET (initial load) and POST (data submission) requests. Key steps:
1. Create a form instance.
2. Check if the request is a POST and if the data is valid (form.validate_on_submit()).
3. Process data if valid (e.g., save to a database); otherwise, display error messages.
Example code:
from flask import Flask, render_template, redirect, url_for
from forms import LoginForm # Import the LoginForm defined earlier
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here' # Required for CSRF protection (use a random key in production)
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm() # Create a form instance
if form.validate_on_submit(): # Check if POST request and data are valid
# Retrieve form data via .data attribute
username = form.username.data
email = form.email.data
password = form.password.data
# Process data (e.g., validate login credentials, save user info)
print(f"User logged in: {username}, {email}")
return redirect(url_for('success')) # Redirect after successful submission
return render_template('login.html', form=form) # Render template with form object
@app.route('/success')
def success():
return "Login successful!"
if __name__ == '__main__':
app.run(debug=True)
5. Rendering Forms in Templates¶
Templates render forms and handle submission/error messages. Use Flask-WTF template tools to simplify rendering:
- form.hidden_tag(): Automatically generates a CSRF protection token (required; otherwise, form submissions will be blocked).
- Loop through form.errors to display error messages.
Create templates/login.html:
<!DOCTYPE html>
<html>
<head>
<title>User Login</title>
<style>
.error { color: red; } /* Style for error messages */
.form-group { margin-bottom: 10px; }
</style>
</head>
<body>
<h1>User Login</h1>
<form method="post">
{{ form.hidden_tag() }} <!-- CSRF protection token -->
<!-- Username -->
<div class="form-group">
{{ form.username.label }}<br>
{{ form.username(size=30) }} <!-- Renders as <input type="text"> -->
{% for error in form.username.errors %}
<span class="error">{{ error }}</span> <!-- Display validation errors -->
{% endfor %}
</div>
<!-- Email -->
<div class="form-group">
{{ form.email.label }}<br>
{{ form.email(size=30) }}
{% for error in form.email.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<!-- Password -->
<div class="form-group">
{{ form.password.label }}<br>
{{ form.password(size=30) }}
{% for error in form.password.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<!-- Submit Button -->
{{ form.submit() }}
</form>
</body>
</html>
Key Points:
- form.hidden_tag() generates a hidden <input> tag for CSRF protection; always include this.
- form.username.label renders the field label (e.g., “用户名”), and form.username(size=30) generates the text input box.
- form.errors is a dictionary storing error messages for each field; loop through it to display errors.
6. Core Principle Summary¶
- Form Definition: Define fields and validation rules via
FlaskFormsubclasses. - Request Handling: View functions distinguish between GET (display empty form) and POST (validate submitted data).
- Data Validation:
form.validate_on_submit()automatically runs all validators (required, format checks, etc.). Data is accessible after validation. - Template Rendering: The
formobject generates HTML form elements; errors are displayed viaform.errors. - CSRF Protection:
form.hidden_tag()generates a token to prevent cross-site request forgery attacks.
7. Common Issues and Solutions¶
- “CSRF token missing” Error: Ensure
form.hidden_tag()is in the template andapp.config['SECRET_KEY']is set. - Form Validation Fails: Check
validatorsconfiguration; errors are inform.errors. - Password Not Hiding: Use
PasswordFieldinstead ofStringField(renders as<input type="password">).
By following these steps, you’ve mastered the core of Flask form handling: defining fields, processing requests, validating data, and rendering forms. For more advanced use cases, integrate with databases (e.g., SQLAlchemy) or add complex fields (e.g., radio buttons, dropdown menus).