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令牌。内置验证器涵盖DataRequiredEmailLengthEqualTo等常见需求,也支持自定义验证方法。文件上传使用FileField配合FileRequiredFileAllowed验证器,配合secure_filename确保安全。Flask-WTF是Flask表单处理的标准方案,强烈推荐在实际项目中使用。

相关推荐
jay神27 分钟前
【计算机毕业设计】基于Flask+Vue的电影数据可视化与智能推荐系统
前端·vue.js·python·信息可视化·flask·毕业设计·课程设计
满怀冰雪1 小时前
24-PaddleClas 模型评估、导出与推理部署入门
大数据·人工智能·python·深度学习·paddle
DeepVisionary7 小时前
谷歌 Gemini Omni 1.1 Flash 正式发布:4K 视频、40 秒场景延伸,视频生成进入按 token 计费时代
python·自动化
阡之尘埃7 小时前
Python数据分析案例85——大模型微调全流程(SFT的LoRA微调)
人工智能·python·深度学习·语言模型·llm·微调·千问
2601_962055977 小时前
跟据spring boot版本,查看对应的tomcat,并查看可支持的tomcat的版本范围
spring boot·后端·tomcat
海兰7 小时前
【应用】基于 Next.js 16 + Python mplfinance的金融K线图与技术指标可视化平台(三)
javascript·python·金融
cvcode_study8 小时前
Ollama+ComfyUI 多模态
大数据·人工智能·python
Lost of 程序猿9 小时前
ASP.NET Core API 幂等性设计深度实战:从一次重复申领事故说起
后端·asp.net
星核0penstarry9 小时前
试一试用gr.Workflow把AI多步骤串联变成可视化画布
人工智能·python·ai作画·api·ai编程·工作流·api聚合平台