Skip to content

用户交互的核心是表单:一次完整交互 = 前端表单接收输入 + 后端处理 + 消息反馈给用户。本章掌握 GET/POST 基本交互与文件上传,用 Flask-WTF 把表单抽象成类(自带验证与 CSRF 保护),用闪现消息和自定义错误页做消息反馈,并集成 CKEditor 富文本编辑器。

GET 与 POST 请求

维度GETPOST
用途从服务器获取数据向服务器提交数据
数据传递URL 查询字符串(?param=value请求体,不显示在 URL
安全性明文可见(历史记录/日志)相对更安全,适合敏感信息
缓存可被浏览器缓存不缓存
幂等性多次请求无副作用多次请求可能改变服务器状态

基本交互与文件上传

接收 GET/POST 数据

python
from flask import request

@app.route('/form', methods=['GET', 'POST'])
def form():
    msg_get = request.args.get('msg_get')    # GET 数据
    msg_post = request.form.get('msg_post')  # POST 数据
    return render_template('form.html', msg_get=msg_get, msg_post=msg_post)

文件上传(两个视图函数)

python
import os
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['UPLOADED_PATH'] = os.path.join(basedir, 'uploads')
os.makedirs(app.config['UPLOADED_PATH'], exist_ok=True)

# ① 获取已上传的文件
@app.route('/files/<filename>')
def uploaded_files(filename):
    return send_from_directory(app.config['UPLOADED_PATH'], filename)

# ② 接收上传
@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        f = request.files.get('upload')
        f.save(os.path.join(app.config['UPLOADED_PATH'], f.filename))
    files = os.listdir(app.config['UPLOADED_PATH'])
    return render_template('upload.html', files=files)

上传表单必须设置 enctype="multipart/form-data"

Flask-WTF 表单

Flask-WTF 把 WTForms 集成进 Flask:将表单抽象为,降低维护难度;自带数据验证CSRF 保护

bash
pip install flask-wtf==0.14.2

1. 定义表单类

所有表单类继承 FlaskForm,字段用类变量描述:

python
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired

class LoginForm(FlaskForm):
    username = StringField(label='用户名')
    password = PasswordField(label='密码')
    submit = SubmitField(label='登录')

使用前必须配置密钥(CSRF 需要):

python
app.config['SECRET_KEY'] = 'Chapter4'   # 生产环境用随机字符串

2. 视图函数

python
@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if request.method == 'POST' and form.validate_on_submit():
        return 'Hello %s! 密码:%s' % (form.username.data, form.password.data)
    return render_template('login.html', form=form)

3. 渲染表单(三种方式)

html
{% extends 'bootstrap/base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}

<!-- 方式1:手动逐个渲染(需含 csrf_token) -->
<form method="post">{{ form.username }}{{ form.password }}{{ form.csrf_token }}{{ form.submit }}</form>

<!-- 方式2:form_field 宏逐个美化 -->
{{ wtf.form_field(form.username) }}

<!-- 方式3:quick_form 快速渲染(推荐,代码最少) -->
{{ wtf.quick_form(form) }}

常用字段类型

字段说明
StringField / TextAreaField文本 / 多行文本
PasswordField密码框
HiddenField隐藏字段
DateField / DateTimeField日期 / 日期时间
IntegerField / FloatField整数 / 浮点数
BooleanField / RadioField复选框 / 单选
SelectField / SelectMultipleField下拉 / 多选下拉
FileField文件上传
SubmitField提交按钮

常用验证器

验证器说明
DataRequired必填,数据不为空
Email验证邮箱格式
EqualTo比较两字段(二次密码确认)
Length校验字符串长度
NumberRange数值范围
IPAddress / RegexpIP 地址 / 正则匹配
Optional选填,为空时跳过其他验证

在字段中添加 validators=[...](list 类型)即可启用多个验证器;复杂表单用 form.data 获取 dict 形式全部数据。

消息反馈

闪现消息(flash)

后端 flash('内容', '类别') 发送,模板用 get_flashed_messages(with_categories=true) 输出;Flask-Bootstrap 提供现成宏:

python
from flask import flash
flash('这是一条测试消息', 'success')   # 类别: success/danger/info/warning
html
<!-- 手动遍历 -->
{% for category, message in get_flashed_messages(with_categories=true) %}
    <h5>[{{ category }}] - {{ message }}</h5>
{% endfor %}
<!-- 或直接用 Bootstrap 宏 -->
{% import 'bootstrap/utils.html' as utils %}
{{ utils.flashed_messages() }}

自定义错误页

app.errorhandler(状态码) 绑定,替代默认纯文字错误页:

python
from flask import abort, request

@app.errorhandler(404)
def not_found_page(e):
    return render_template('custom_error.html', title='Emmmm, 404!',
                           description='搞错url了吧:%s' % request.path), 404

# 在视图函数中主动触发:abort(404) / abort(500)

500 页调试时可显示异常(traceback.print_exc),上线后必须隐藏错误详情,改用日志记录

Flask-CKEditor 富文本

CKEditor 让用户在浏览器中编辑富文本(格式化、插图、表格)。

bash
pip install flask-ckeditor==0.4.3
python
from flask_ckeditor import CKEditor, CKEditorField

app.config['CKEDITOR_SERVE_LOCAL'] = True      # 用本地资源
app.config['CKEDITOR_FILE_UPLOADER'] = 'upload_ckeditor'   # 指定上传视图

ckeditor = CKEditor()
ckeditor.init_app(app)

class ArticleForm(FlaskForm):
    title = StringField(label='标题', validators=[DataRequired()])
    content = CKEditorField(label='内容', validators=[DataRequired()])
    submit = SubmitField(label='查看')

模板中额外加载与配置:

html
{{ ckeditor.load() }}
{{ ckeditor.config(name='content', height=320) }}

查看页输出富文本内容时须用 | safe 关闭 HTML 转义(数据为 HTML 格式):

html
{{ form.content.data | safe }}

上传图片:视图函数校验扩展名后用 upload_success(url=...) / upload_fail(message=...) 返回 CKEditor 要求的格式。

实践建议

  1. 表单一律用 Flask-WTF + quick_form,不要手写 HTML 表单——代码量减少、自带验证与 CSRF
  2. SECRET_KEY 生产环境必须用随机字符串,不能硬编码
  3. 操作结果用 flash 反馈,错误页面用 errorhandler 定制保持风格统一
  4. 富文本内容输出务必用 | safe(前提:内容来源可信),否则有 XSS 风险

一句话总结

别再手写 HTML 表单——用 Flask-WTF 把表单写成类(自带验证与 CSRF,需配 SECRET_KEY),渲染首选 wtf.quick_form(form);操作结果用 flash 反馈,富文本输出必须 | safe(否则有 XSS 风险)。

相关概念