1. 基本表单处理
Flask提供了直接处理表单数据的方式,使用request对象来获取提交的数据。
创建HTML表单
templates/form.html:
<!DOCTYPE html> <html> <head> <title>Form Example</title> </head> <body> <form action="/submit" method="post"> <label for="name">Name:</label> <input type="text" id="name" name="name"> <br> <label for="email">Email:</label> <input type="email" id="email" name="email"> <br> <input type="submit" value="Submit"> </form> </body> </html>
-
action="/submit":表单数据提交到/submit路径 -
method="post":使用POST方法提交数据(敏感数据不应使用GET)
处理表单数据
from flask import Flask, render_template, request app = Flask(__name__) @app.route('/') def form(): return render_template('form.html') @app.route('/submit', methods=['POST']) def submit(): name = request.form.get('name') email = request.form.get('email') return f'Name: {name}, Email: {email}' if __name__ == '__main__': app.run(debug=True)
2. 使用Flask-WTF扩展
Flask-WTF是一个封装了WTForms的扩展,提供了表单处理和验证的功能,使得表单处理更加简洁和强大。
安装Flask-WTF
pip install flask-wtf
配置与定义表单
from flask import Flask, render_template, redirect, url_for from flask_wtf import FlaskForm from wtforms import StringField, EmailField, SubmitField from wtforms.validators import DataRequired, Email app = Flask(__name__) app.secret_key = 'your_secret_key' # CSRF保护需要密钥 class MyForm(FlaskForm): name = StringField('Name', validators=[DataRequired()]) email = EmailField('Email', validators=[DataRequired(), Email()]) submit = SubmitField('Submit') @app.route('/', methods=['GET', 'POST']) def form(): form = MyForm() if form.validate_on_submit(): name = form.name.data email = form.email.data return f'Name: {name}, Email: {email}' return render_template('form.html', form=form)
模板中渲染WTForms
templates/form.html:
<!DOCTYPE html> <html> <head> <title>Form Example</title> </head> <body> <form method="post"> {{ form.hidden_tag() }} <div> {{ form.name.label }}<br> {{ form.name(size=32) }} </div> <div> {{ form.email.label }}<br> {{ form.email(size=32) }} </div> <div> {{ form.submit() }} </div> </form> </body> </html>
| 模板语法 | 作用 |
|---|---|
{``{ form.hidden_tag() }} |
生成CSRF令牌隐藏字段 |
{``{ form.name.label }} |
渲染字段的标签 |
{``{ form.name(size=32) }} |
渲染字段控件,可传入HTML属性 |
{``{ form.submit() }} |
渲染提交按钮 |
3. 常用字段类型
WTForms提供了丰富的字段类型,覆盖了绝大多数表单场景:
| 字段类 | 说明 | HTML渲染 |
|---|---|---|
StringField |
文本输入 | <input type="text"> |
EmailField |
邮箱输入 | <input type="email"> |
PasswordField |
密码输入 | <input type="password"> |
IntegerField |
整数输入 | <input type="number"> |
FloatField |
浮点数输入 | <input type="number" step="any"> |
BooleanField |
复选框 | <input type="checkbox"> |
SelectField |
下拉选择 | <select> |
RadioField |
单选按钮 | <input type="radio"> |
TextAreaField |
多行文本 | <textarea> |
SubmitField |
提交按钮 | <input type="submit"> |
FileField |
文件上传 | <input type="file"> |
DateField |
日期输入 | <input type="date"> |
DateTimeField |
日期时间输入 | <input type="datetime-local"> |
完整表单示例
from wtforms import StringField, PasswordField, BooleanField, SelectField, TextAreaField, SubmitField from wtforms.validators import DataRequired, Email, Length, EqualTo class RegisterForm(FlaskForm): username = StringField('用户名', validators=[ DataRequired(), Length(min=3, max=20, message="用户名长度必须在3-20个字符之间") ]) email = EmailField('邮箱', validators=[DataRequired(), Email()]) password = PasswordField('密码', validators=[ DataRequired(), Length(min=6, message="密码至少6个字符") ]) confirm = PasswordField('确认密码', validators=[ DataRequired(), EqualTo('password', message="两次密码输入不一致") ]) gender = SelectField('性别', choices=[('male', '男'), ('female', '女'), ('other', '其他')]) bio = TextAreaField('个人简介') agree = BooleanField('同意用户协议', validators=[DataRequired()]) submit = SubmitField('注册')
4. 表单验证器
Flask-WTF和WTForms提供了丰富的表单验证功能。
内置验证器
| 验证器 | 作用 |
|---|---|
DataRequired() |
确保字段不为空 |
Email() |
验证是否为有效的邮箱地址 |
Length(min, max) |
限制字符串长度范围 |
EqualTo(fieldname) |
验证是否与另一个字段值相同 |
NumberRange(min, max) |
限制数值范围 |
URL() |
验证是否为有效的URL |
Regexp(regex) |
使用正则表达式验证 |
IPAddress() |
验证是否为有效的IP地址 |
UUID() |
验证是否为有效的UUID |
AnyOf(values) |
验证值是否在指定列表中 |
NoneOf(values) |
验证值不在指定列表中 |
自定义验证器
除了内置验证器,还可以在表单类中定义validate_字段名方法实现自定义验证:
class RegisterForm(FlaskForm): username = StringField('用户名', validators=[DataRequired()]) email = EmailField('邮箱', validators=[DataRequired(), Email()]) submit = SubmitField('注册') # 自定义验证:检查用户名是否包含敏感词 def validate_username(self, field): if 'admin' in field.data.lower(): raise ValidationError('用户名不能包含 "admin"') # 自定义验证:检查邮箱是否已被注册(实际场景中需查询数据库) def validate_email(self, field): if field.data == 'test@example.com': raise ValidationError('该邮箱已被注册')
5. 显示验证错误
在模板中显示字段的验证错误:
<form method="post"> {{ form.hidden_tag() }} <div> {{ form.username.label }}<br> {{ form.username(size=32) }} {% if form.username.errors %} <ul style="color:red;"> {% for error in form.username.errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} </div> <div> {{ form.email.label }}<br> {{ form.email(size=32) }} {% if form.email.errors %} <ul style="color:red;"> {% for error in form.email.errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} </div> <div> {{ form.submit() }} </div> </form>
6. 文件上传
Flask支持处理文件上传,文件通过request.files访问。
创建文件上传表单
templates/upload.html:
<!DOCTYPE html> <html> <head> <title>Upload File</title> </head> <body> <form action="/upload" method="post" enctype="multipart/form-data"> <label for="file">File:</label> <input type="file" id="file" name="file"> <br> <input type="submit" value="Upload"> </form> </body> </html>
enctype="multipart/form-data"是文件上传必需的编码类型。
使用Flask-WTF的FileField
import os from flask import Flask, render_template, request from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileRequired, FileAllowed from wtforms import SubmitField from werkzeug.utils import secure_filename app = Flask(__name__) app.secret_key = 'secret' app.config['UPLOAD_FOLDER'] = 'uploads/' class UploadForm(FlaskForm): file = FileField('选择文件', validators=[ FileRequired('请选择一个文件'), FileAllowed(['jpg', 'png', 'pdf', 'txt'], '只允许上传 jpg, png, pdf, txt 文件') ]) submit = SubmitField('上传') @app.route('/upload', methods=['GET', 'POST']) def upload(): form = UploadForm() if form.validate_on_submit(): file = form.file.data filename = secure_filename(file.filename) os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) return f'文件 {filename} 上传成功!' return render_template('upload.html', form=form)
文件上传验证器
| 验证器 | 作用 |
|---|---|
FileRequired() |
确保已选择文件 |
FileAllowed(['jpg', 'png']) |
限制允许的文件扩展名 |
7. CSRF保护
Flask-WTF自动为表单提供CSRF(跨站请求伪造)保护。
启用CSRF保护
app.secret_key = 'your_secret_key' # CSRF令牌加密需要
模板中添加CSRF令牌
<form method="post"> {{ form.hidden_tag() }} <!-- 其他表单字段 --> </form>
form.hidden_tag()会生成一个隐藏的CSRF令牌字段,提交时Flask-WTF会自动验证。
全局CSRF保护
也可以为所有视图启用CSRF保护,包括非WTForms表单:
from flask_wtf.csrf import CSRFProtect csrf = CSRFProtect(app) # 或在应用工厂模式中 # csrf = CSRFProtect() # csrf.init_app(app)
对于AJAX请求,需要将CSRF令牌放在请求头中:
// 在模板中获取CSRF令牌 const csrfToken = "{{ csrf_token() }}"; fetch('/api/data', { method: 'POST', headers: { 'X-CSRFToken': csrfToken, 'Content-Type': 'application/json' }, body: JSON.stringify(data) });
8. 表单处理完整流程对照
| 步骤 | 纯Flask手动方式 | Flask-WTF方式 |
|---|---|---|
| 1. 定义表单 | 写HTML模板 | Python表单类 |
| 2. 渲染表单 | 手写HTML | {``{ form.field }} |
| 3. 获取数据 | request.form.get('name') |
form.name.data |
| 4. 验证数据 | 手写if判断 | form.validate_on_submit() |
| 5. 错误处理 | 手动处理 | 自动收集到form.field.errors |
| 6. CSRF保护 | 需手动实现 | 自动处理(hidden_tag()) |
小结
本章全面讲解了Flask的表单处理。基础方式使用request.form手动获取和验证数据,适合简单场景;Flask-WTF扩展提供了更完善的方案------通过表单类定义字段和验证器,validate_on_submit()自动完成验证,模板中form.hidden_tag()自动生成CSRF令牌。内置验证器涵盖DataRequired、Email、Length、EqualTo等常见需求,也支持自定义验证方法。文件上传使用FileField配合FileRequired和FileAllowed验证器,配合secure_filename确保安全。Flask-WTF是Flask表单处理的标准方案,强烈推荐在实际项目中使用。