Flask学习(3)——表单

在Flask中,通常使用Flask-WTF扩展来对Web表单进行处理,这样更加方便。首先在虚拟环境中安装此扩展:

pip install flask-wtf

一、配置

Flask-WTF扩展不用在应用层初始化,但是需要配置一个密钥(SECRET_KEY),Flask 使用这个密钥保护用户会话,以防被篡改,也就是防止 CSRF 攻击。

app = Flask(_name__)
app.config['SECRET_KEY'] = 'I am Lethe'

app.config 字典可用于存储 Flask、扩展和应用自身的配置变量。实际上为了增强安全性,密钥不应该直接写入源码,而要保存在环境变量中。


二、表单类

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

下面的表单示例中包含一个文本字段和一个提交按钮:

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

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

上面代码中:

  • StringField 类表示属性为 type="text" HTML <input> 元素。
  • SubmitField 类表示属性为 type="submit" 的HTML元素 <input> 元素。
  • 字段构造函数的第一个参数代表使用的标注(label)
  • StringField 构造函数中的可选参数 validators 指定一个由验证函数组成的列表,在接收数据前对数据进行验证(DataRequired 确保提交的数据不为空)

WTForms 支持的 HTML 标准字段:

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

WTForms 验证函数:

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

三、表单渲染

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

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

这里的 form.hidden_tag() 元素生成一个隐藏的字段,用于 CSRF 防护。

在调用字段的时候,传入的关键词参数将转换为字段的HTML属性。 如下,指定id或class属性,从而可以定义CSS样式:

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

在实际渲染及美化表单时,可以直接使用 Bootstrap 的表单样式,通过Flask-Bootstrap扩展,如下:

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

使用 import 导入 bootstrap/wtf.html 文件,其中定义了一个用默认Bootstrap 样式渲染的 Flask-WTF 表单对象的辅助函数 wtf.quick_form() ,参数为Flask-WTF 表单对象。

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

{% 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 %}

四、处理表单

定义了表单的类,需要在视图函数中对表单进行处理和渲染,下例使用 GET 和 POST 方法处理表单:

hello.py

@app.route('/', methods=['GET', 'POST'])
def index():
    name = None
	form = NameForm()
	if form.validate_on_submit():
		name = form.name.data # 将表单中name字段值赋给name
		form.name.data = '' # 清空表单
	return render_template('index.html', form=form, name=name)
  • 局部变量 name 用于存放表单中的名字字段,默认值为 None。
  • validate_on_submit() 方法:提交表单后,数据能被所有验证函数接收,返回True;否则返回False。
  • 最后用 render_template() 渲染表单时,将变量name,和对象form传入到模板中。

效果如下:
在这里插入图片描述
提交Lethe后:
在这里插入图片描述

五、重定向和用户会话

在实际情况中,最好别让Web应用把 POST 请求作为浏览器发送的最后一个请求,因此可以使用重定向作为POST请求的响应。

如在用POST方式提交完表单后,再向重定向的URL发送GET请求,显示页面的内容,用户不会察觉到有所不同,这叫做 “POST / 重定向 / GET” 模式。

在这种模式下,应用处理POST请求时,需要用变量保存输入的数据,否则一旦重定向后,就无法再通过form.name.data获取POST请求中的字段值。

应用也可以把数据存储在用户会话(session)中,以便在请求之间“记住”数据。用户会话是一种私有存储,每个连接到服务器的客户端都可访问。

改进后的hello.py:

from flask import Flask, render_template, session, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

app = Flask(__name__)
bootstrap = Bootstrap(app)
app.config['SECRET_KEY'] = 'I am Lethe'

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

@app.route('/', methods=['GET', 'POST'])
def index():
	form = NameForm()
	if form.validate_on_submit():
		session['name'] = form.name.data
		return redirect(url_for('index'))
	return render_template('index.html', form=form, name=session.get('name'))
  • 相比于上一个例子中,将 name保存在局部变量中,这里将其保存在了用户会话中,即 session[‘name’]。
  • 若表单数据有效,则会用 redirect() 函数进行重定向,其参数为URL,因此可以使用辅助函数 url_for() 来生成URL,这里即重定向到根URL。
  • 视图函数在向模板传参时,通过 session.get(‘name’) 从session中取出数据

六、闪现消息

请求完成后,有时需要向用户发送一些提示信息,如用户名或密码无效等,这可以用到闪现消息。

Flask中通过 flash()函数实现此功能:

from flask import Flask, render_template, session, redirect, url_for, flash
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_moment import Moment

app = Flask(__name__)
bootstrap = Bootstrap(app)
moment = Moment(app)
app.config['SECRET_KEY'] = 'I am Lethe'


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


@app.route('/', methods=['GET', 'POST'])
def index():
	form = NameForm()
	if form.validate_on_submit():
		old_name = session.get('name')
		if old_name is not None and old_name != form.name.data:
			flash('Looks like you have changed your name!')
		session['name'] = form.name.data
		return redirect(url_for('index'))
	return render_template('index.html', form=form, name=session.get('name'))
  • 当两次提交的name不一样时,就会调用 flash()函数,在发给客户端的下一个响应中显示一个消息。
  • 仅调用 flash() 函数不能将消息显示出来,还需要经过模板的渲染。最好在基模板中渲染闪现消息,这样继承自它的所有页面都能显示要闪现的消息。

Flask中用 get_flashed_message() 函数在模板中获取并渲染闪现消息,如下修改emplates/base.html中的 content 块:

{% block content %}
<div class="container">
    {% for message in get_flashed_message() %}
    <div class="alert alert-warning">
        <button type="button" class="close" data-dismiss="alert">&times;</button>
        {{ message }}
    </div>
    {% endfor %}
    {% block page_content %}{% endblock %}
</div>
{% endblock %}
  • 此实例使用Bootstrap 提供的 CSS alert 样式渲染警告消息。
  • 使用了循环,因为在之前的请求循环中每次调用 flash() 函数时都会生成一个消息,所以可能有多个消息在排队等待显示。
  • get_flashed_messages() 函数获取的消息在下次调用时不会再次返回,因此闪现消息只显示一次,然后就消失了

两次提交不同的值,效果如下:

在这里插入图片描述

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值