2.flask:表单

2.flask:表单

Flask-WTF 及其依赖可使用 pip 安装:

pip install flask-wtf

1. 配置

Flask-WTF 无须在应用层初始化,但是它要求应用配置一个密钥。Flask 使用这个密钥保护用户会话,以防被篡改。

hello.py

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

app.config 字典可用于存储 Flask、扩展和应用自身的配置变量。使用标准的字典句法就能把配置添加到 app.config 对象中。这个对象还提供了一些方法,可以从文件或环境中导入配置。

Flask-WTF 之所以要求应用配置一个密钥,是为了防止表单遭到跨站请求伪造(CSRF,cross-site request forgery)攻击。恶意网站把请求发送到被攻击者已登录的其他网站时,就会引发 CSRF 攻击。Flask-WTF 为所有表单生成安全令牌,存储在用户会话中。

2. 表单类

使用 Flask-WTF 时,在服务器端,每个 Web 表单都由一个继承自 FlaskForm 的类表示。这个类定义表单中的一组字段,每个字段都用对象表示。字段对象可附属一个或多个验证函数。验证函数用于验证用户提交的数据是否有效。

示例是一个简单的 Web 表单,包含一个文本字段和一个提交按钮。

hello.py

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

class NameForm(FlaskForm):
    name = StringField('What is your name?', validators=[DataRequired()])
    submit = SubmitField('Submit')

这个表单中的字段都定义为类变量,而各个类变量的值是相应字段类型的对象。在这个示例中,NameForm 表单中有一个名为 name 的文本字段和一个名为 submit 的提交按钮。StringField 类表示属性为 type="text" 的 HTML <input> 元素。SubmitField 类表示属性为 type="submit" 的 HTML <input> 元素。字段构造函数的第一个参数是把表单渲染成 HTML 时使用的标注(label)。

StringField 构造函数中的可选参数 validators 指定一个由验证函数组成的列表,在接受用户提交的数据之前验证数据。验证函数 DataRequired() 确保提交的字段内容不为空。

FlaskForm 基类由 Flask-WTF 扩展定义,所以要从 flask_wtf 中导入。然而,字段和验证函数却是直接从 WTForms 包中导入的。

WTForms 支持的 HTML 标准字段如表所示。

表:WTForms支持的HTML标准字段

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

WTForms 内建的验证函数如表所示。

表:WTForms验证函数

验证函数说明
DataRequired确保转换类型后字段中有数据
Email验证电子邮件地址
EqualTo比较两个字段的值;常用于要求输入两次密码进行确认的情况
InputRequired确保转换类型前字段中有数据
IPAddress验证 IPv4 网络地址
Length验证输入字符串的长度
MacAddress验证 MAC 地址
NumberRange验证输入的值在数字范围之内
Optional允许字段中没有输入,将跳过其他验证函数
Regexp使用正则表达式验证输入值
URL验证 URL
UUID验证 UUID
AnyOf确保输入值在一组可能的值中
NoneOf确保输入值不在一组可能的值中

3. 把表单渲染成HTML

表单字段是可调用的,在模板中调用后会渲染成 HTML。假设视图函数通过 form 参数把一个 NameForm 实例传入模板,在模板中可以生成一个简单的 HTML 表单,如下所示:

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

注意,除了 namesubmit 字段,这个表单还有个 form.hidden_tag() 元素。这个元素生成一个隐藏的字段,供 Flask-WTF 的 CSRF 防护机制使用。

当然,这种方式渲染出的表单还很简陋。调用字段时传入的任何关键字参数都将转换成字段的 HTML 属性。例如,可以为字段指定 idclass 属性,然后为其定义 CSS 样式:

<form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name(id='my-text-field') }}
    {{ form.submit() }}
</form>

即便能指定 HTML 属性,但按照这种方式渲染及美化表单的工作量还是很大,所以在条件允许的情况下,最好使用 Bootstrap 的表单样式。Flask-Bootstrap 扩展提供了一个高层级的辅助函数,可以使用 Bootstrap 预定义的表单样式渲染整个 Flask-WTF 表单,而这些操作只需一次调用即可完成。使用 Flask-Bootstrap,上述表单可以用下面的方式渲染:

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

import 指令的使用方法和普通 Python 代码一样,通过它可以导入模板元素,在多个模板中使用。导入的 bootstrap/wtf.html 文件中定义了一个使用 Bootstrap 渲染 Flask-WTF 表单对象的辅助函数。wtf.quick_form() 函数的参数为 Flask-WTF 表单对象,使用 Bootstrap 的默认样式渲染传入的表单。hello.py 的完整模板如示例所示。

示例 templates/index.html:使用 Flask-WTF 和 Flask-Bootstrap 渲染表单

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

{% block title %}Flasky{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}

base.html

{% extends "bootstrap/base.html" %}

{% block title %}Flasky{% endblock %}

{% block navbar %}
<div class="navbar navbar-inverse" role="navigation">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle"
             data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="/">Flasky</a>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Home</a></li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}

{% block content %}
<div class="container">
    {% block page_content %}{% endblock %}
</div>
{% endblock %}

4. 在视图函数中处理表单

在新版 hello.py 中,视图函数 index() 有两个任务:一是渲染表单,二是接收用户在表单中填写的数据。以下示例是更新后的 index() 视图函数。

示例 hello.py:使用 GETPOST 请求方法处理 Web 表单

@app.route('/', methods=['GET', 'POST'])
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form=form, name=name)

app.route 装饰器中多出的 methods 参数告诉 Flask,在 URL 映射中把这个视图函数注册为 GETPOST 请求的处理程序。如果没指定 methods 参数,则只把视图函数注册为 GET 请求的处理程序。

这里有必要把 POST 加入方法列表,因为更常使用 POST 请求处理表单提交。表单也可以通过 GET 请求提交,但是 GET 请求没有主体,提交的数据以查询字符串的形式附加到 URL 中,在浏览器的地址栏中可见。基于这个以及其他多个原因,处理表单提交几乎都使用 POST 请求。

图1 是用户首次访问网站时浏览器显示的表单。用户提交名字后,应用会生成一个针对该用户的欢迎消息。欢迎消息下方还是会显示这个表单,以便用户输入新名字。图 2 显示了此时应用的样子。

image.png

图1:Flask-WTF Web 表单

image.png

图2:提交后显示的 Web 表单

如果用户提交表单之前没有输入名字,那么 DataRequired() 验证函数会捕获这个错误,如图3 所示。注意这个扩展自动提供了多少功能。这说明,像 Flask-WTF 和 Flask-Bootstrap 这样设计良好的扩展能给应用提供十分强大的功能。

image.png

62204877520)]

图2:提交后显示的 Web 表单

如果用户提交表单之前没有输入名字,那么 DataRequired() 验证函数会捕获这个错误,如图3 所示。注意这个扩展自动提供了多少功能。这说明,像 Flask-WTF 和 Flask-Bootstrap 这样设计良好的扩展能给应用提供十分强大的功能。

[外链图片转存中…(img-vAjdWjYo-1662204877520)]

图3:验证失败后显示的 Web 表单

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值