Flask入门教程(十二):表单处理——从基础到Flask-WTF完整实践

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)

处理表单数据

app.py:

复制代码
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

配置与定义表单

app.py:

复制代码
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表单处理的标准方案,强烈推荐在实际项目中使用。

相关推荐
小码哥_常4 小时前
一套自己部署的 IM,客户端是同一份 Flutter
前端·后端
代码山河7 小时前
Python就业方向全解析:后端、爬虫、数据分析、AI你选哪个?
python·学习·架构·教程·面向对象·项目
在世修行7 小时前
智学文枢:题目流水线
python·多线程·状态机·pyside
学长毕设7 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
梯度下降者7 小时前
零基础入门Python 爬虫
爬虫·python·数据分析·入门指南·webcrawler
“AI国潮设计-小江”9 小时前
【AIGC实战】Python+Stable Diffusion打造“英歌舞财神”IP,解锁“马到成功”等爆款情绪营销文案设计
开发语言·人工智能·python·prompt·aigc
努力的小雨9 小时前
给 AI 眼镜开发应用有多难?我从零做了一个陪练,还上架了
后端
benchmark_cc10 小时前
用 Python 拉 A 股全市场实时快照:Notebook 请求、结果校验与易错点
python·数据分析·pandas·量化交易·股票数据·quantdash
伞伞悦读10 小时前
【第70期】Adam二阶矩不是方差:偏差校正、动量与AdamW完整实验
python
excel10 小时前
双 Token 与前端使用 Crypto 公私钥鉴权换 Token,哪种方案更好?
前端·后端