2.用Flask-WTF处理表单

本文介绍了如何使用Flask-WTF扩展来处理Web表单,包括设置密钥以防止CSRF攻击,定义表单类及验证函数,渲染和处理表单数据。此外,还讲解了用户会话(session)的使用,以及在表单提交后利用Flash提醒用户操作状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本处理

之前提到的请求上下文中的request.form可以获得POST请求中提交表单数据,一个个去处理显然很繁琐,这时可以用Flask-WTF来让一切变得更加简单,它集成了WTForms,安装如下:
pip install flask-wtf

设置密钥

为了防止恶意网站的CSRF攻击,Flask-WTF用一个密钥生成加密令牌,再用令牌验证数据的真伪,我们把这个密钥放在app.config字典中,这里面存储了一些框架的配置变量,还支持导入配置值(一般密钥是保存在环境变量里的),代码如下:

# demo.py
...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'some secret string' 
...

使用表单类

在这个拓展中每个表单都由一个继承Form的类,里面的每个字段都定义为类变量,还可以附属验证函数,如下:

from flask_wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required

class NameForm(Form):
    name = StringField('你的名字:', validators=[Required()]) # validator为验证函数组成的列表
    submit = SubmitField('Go')

WTForms支持的HTML标准字段

字段类型说 明
StringField文本字段
TextAreaField多行文本字段
PasswordField密码文本字段
HiddenField隐藏文本字段
DateField文本字段,值为datetime.date格式
DateTimeField文本字段,值为datetime.datetime格式
IntegerField文本字段,值为整数
DecimalField文本字段,值为decimal.Decimal
FloatFiled文本字段,值为浮点数
BooleanField复选框,值为True和False
RadioField一组单选框
SelectField下拉列表
SelectMultipleField下拉列表,可选择多个值
FileField文件上传字段
SubmitField表单提交按钮
FormField把表单作为字段嵌入另一表单
FieldList一组指定类型的字段

WTForms验证函数:

验证函数说 明
Email验证电子邮件地址
EqualTo比较两个字段的值,常用于要求输入两次密码确认的情况
IPAddress验证IPv4网络地址
Length验证输入字符串的长度
NumberRange验证输入的值在数字范围内
Optional无输入值时跳过其他验证函数
Required确保字段中有数据
Regexp使用正则表达式验证输入值
URL验证URL
AngOf确保输入值在可选值列表中
NoneOf确保输入值之不在可选值列表中

页面部分:渲染表单

接下来要在页面上显示,我们可以把表单实例通过参数form传入模板,如下:

<form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name() }}
    {{ form.submit() }}
</form>

有些麻烦是吧,好在Flask-Bootstrap提供了一个好用的函数quick_form(),它接收一个表单对象,方便快速的渲染表单:

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %} <!-- 导入模板中的元素并别名为wtf -->

{% block title %}首屋{% endblock %}
{% block page_content %}
<div class="page-header">
   <h1>你来了, {% if name %} {{ name }}{% else %}外乡人{% endif %}!!</h1>
</div>
{{ wtf.quick_form(form) }} <!-- 这里对form对象进行渲染-->
{% endblock %}

运行如图:
这里写图片描述

后端部分:处理表单

接收到POST请求后要进行处理,由于之前的首页路由只有默认的GET请求方法,我们要添加POST方法,虽然表单也可以用GET提交(以查询字符串形式加到URL中),但它没有主体以及其他安全问题,还是稳稳用POST吧

改写的index路由如下:

@app.route('/', methods=['GET', 'POST'])  # methods参数注册请求方法
def index():
    name = None
    form = NameForm()  # 实例化一个表单
    if form.validate_on_submit():  # 表单成功提交后进入
        name = form.name.data    # 通过字段的data属性获取
        form.name.data = '' # 获取数据后清空表单
    return render_template('index.html', form=form, name=name, cur_time=datetime.utcnow(), time=datetime(1995,7,1))

这个过程:第一次GET获取页面和表单,第二次POST提交表单进入if获得参数进行渲染

提交表单后:
这里写图片描述

用户会话(session)的使用

它是之前提到过的请求上下文中的变量(另一个是request),session以字典的形式存储请求之间的数据,存于客户端的cookie中并用使SECRET_KEY加密,为什么要用它,需要了解一下重定向

重定向是一种特殊响应,响应内容是URL,浏览器接收到这种响应时会向重定向的URL发起GET请求来显示页面的内容

因为刷新页面时浏览器会重新发送之前发送的最后一个请求,如果是POST(包含表单数据)那刷新后就会再次提交,显然这是不好的,不要把POST请求作为浏览器的最后一个请求,这时可以用重定向来实现,这种避免POST放在最后而用GET的技巧被称作 Post/重定向/Get模式,但当一个请求结束时数据也会跟着丢失,此时session就派上了用场:

from flask import Flask, render_template, redirect, url_for, session  # 记得导入所用的
@app.route('/', methods=['GET', 'POST'])  # methods参数注册请求方法
def index():
    form = NameForm()  # 实例化一个表单
    if form.validate_on_submit():  # 判断表单是否成功提交
        session['name'] = form.name.data   # 把值保存在session中
        return redirect(url_for('index'))  # 为了兼容
    return render_template('index.html', form=form, name=session.get('name'), cur_time=datetime.utcnow(), time=datetime(1995,7,1))

url_for()用于生成URL,它只有一个参数,即端点名(在这里视图函数名),用这个函数可以防止修改路由后URL不可用的问题;session.get('name')很灵活,当值未找到时返回None,因此省去了name=None

提交表单后的请求:
这里写图片描述

Flash提醒

当请求完成后想有点反馈,告知客户端成功或失败,flask有个flash()函数就是专门干这事的,先看后端代码:

from flask import flash  # 记得导入
@app.route('/', methods=['GET', 'POST'])  # methods参数注册请求方法
def index():
    form = NameForm()  
    if form.validate_on_submit():  
        oldname = session.get('name')  
        if oldname is not None and oldname != form.name.data: # 提交的名字与之前的名字比较
            flash("我们不一样")
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form=form, name=session.get('name'), cur_time=datetime.utcnow(), time=datetime(1995,7,1))

然后在模板中渲染,Flask把get_flashed_messages()函数开放给了模板,放在content块中:

{% block content %}
<div class="container">
    {% for message in get_flashed_messages() %}
    <div class='alert alert-warning'>
        <button type='button' class='close' data-dismiss='alert'>&times;</button> <!--&times是×-->
        {{ message }}
    </div>
    {% endfor %}
    {% block page_content %}{% endblock %}
</div>
{% endblock %}    

输入两次不同后如下:
这里写图片描述
在之前的请求循环中每次调用flash()函数都会生成一个消息,会形式多个消息排队等待的情况,所以用for;get_flashed_messages()获取的消息在下次调用时不会再次返回,所以Flash消息只显示一次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值