flask学习笔记(-Web 表单)
Posted SUN_DRAGON
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flask学习笔记(-Web 表单)相关的知识,希望对你有一定的参考价值。
WEB表单
安装flask-wtf
Flask可以通过request.form 能获取POST 请求中提交的表单数据。尽管 Flask 的请求对象提供的信息足够用于处理 Web 表单,但有些任务很单调,而且要重复操作。比如,生成表单的 html 代码和验证提交的表单数据。Flask-WTF扩展可以把处理 Web 表单的过程变成一种愉悦的体验。
pip install flask-wtf
跨站请求伪造保护
Flask-WTF 能保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击。恶意网站把请求发送到被攻击者已登录的其他网站时就会引发 CSRF 攻击。解释,flask-wtf教程
为了实现 CSRF 保护,Flask-WTF 需要程序设置一个密钥。Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。
#设置 Flask-WTF
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'#字典可用来存储框架、扩展和程序本身的配置变量。
#为了增强安全性,密钥不应该直接写入代码,而要保存在环境变量中。
表单类
每个 Web 表单都由一个继承自 Form 的类表示。这个类定义表单中的一组字段(表单的内容与类的字段是一一对应的),每个字段都用对象(表单中的对象)表示。字段对象可附属一个或多个验证函数。
字段对象 | 说明 |
---|---|
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码文本字段 |
HiddenField | 隐藏文本字段 |
DateField | 文本字段,值为 datetime.date 格式 |
DateTimeField | 文本字段,值为 datetime.datetime 格式 |
IntegerField | 文本字段,值为整数 |
DecimalField | 文本字段,值为 decimal.Decimal |
FloatField | 文本字段,值为浮点数 |
BooleanField | 复选框,值为 True 和 False |
RadioField | 一组单选框 |
SelectField | 下拉列表 |
SelectMultipleField | 下拉列表,可选择多个值 |
FileField | 文件上传字段 |
SubmitField | 表单提交按钮 |
FormField | 把表单作为字段嵌入另一个表单 |
FieldList | 一组指定类型的字段 |
验证函数 | 说 明 |
---|---|
验证电子邮件地址 | |
EqualTo | 比较两个字段的值;常用于要求输入两次密码进行确认的情况 |
IPAddress | 验证 IPv4 网络地址 |
Length | 验证输入字符串的长度 |
NumberRange | 验证输入的值在数字范围内 |
Optional | 无输入值时跳过其他验证函数 |
Required | 确保字段中有数据 |
Regexp | 使用正则表达式验证输入值 |
URL | 验证 URL |
AnyOf | 确保输入值在可选值列表中 |
NoneOf | 确保输入值不在可选值列表中 |
定义表单
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required
class NameForm(Form):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
渲染表单
表单字段是可调用的,在模板中调用后会渲染成 HTML。假设视图函数把一个 NameForm 实例通过参数 myform 传入模板,在模板中可以生成一个简单的表单。
<form method="POST">
<!--Form 类有一个 hidden_tag 方法, 它在一个隐藏的 DIV 标签中渲染任何隐藏的字段,包括 CSRF 字段-->
myform.hidden_tag()
<!--可以为字段指定 id 或 class 属性,然后定义 CSS 样式-->
myform.name.label myform.name(id='my-text-field')
myform.submit()
</form>
可以使用 Bootstrap 中预先定义好的表单样式渲染整个 Flask-WTF 表单。导入模板中的bootstrap/wtf.html 元素。定义了一个使用 Bootstrap 渲染 Falsk-WTF 表单对象的辅助函数。 wtf.quick_form() 函数的参数为 Flask-WTF 表单对象,使用 Bootstrap 的默认样式渲染传入的表单。上述的操作只需一步即可。
% import "bootstrap/wtf.html" as wtf %
wtf.quick_form(myform)
% 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(myform)
% endblock %
在视图函数中处理表单
#methods 参数告诉 Flask 在 URL 映射中把这个视图函数注册为GET 和 POST 请求的处理程序。默认只有GET方法
#把 POST 加入方法列表很有必要,因为将提交表单作为 POST 请求进行处理更加便利。表单也可作为 GET 请求提交,不过 GET 请求没有主体,提交的数据以查询字符串的形式附加到URL 中,可在浏览器的地址栏中看到。
@app.route('/', methods=['GET', 'POST'])
def index():
name = None
form = NameForm()
if form.validate_on_submit():#如果数据能被所有验证函数接受,那么 validate_on_submit() 方法的返回值为 True ,否则返回 False 。validate_on_submit() 会调用name 字段上附属的 Required() 验证函数。
name = form.name.data
form.name.data = ''
return render_template('index.html', form=form, name=name)
调用流程
用户第一次请求:
client->method GET->router->view->new a form instance->as a parameter send to template->jinjia2 render->return content
用户按下submit
client->method POST->router->view->new a form instance->as a parameter send to template->jinjia2 render->return content
重定向和用户会话
用户输入名字后提交表单,然后点击浏览器的刷新按钮,会看到一个莫名其妙的警告,要求在再次提交表单之前进行确认。之所以出现这种情况,是因为刷新页面时浏览器会重新发送之前已经发送过的最后一个请求。如果这个请求是一个包含表单数据的 POST 请求,刷新页面后会再次提交表单。
基于这个原因,最好别让 Web 程序把 POST 请求作为浏览器发送的最后一个请求。这种需求的实现方式是,使用重定向作为 POST 请求的响应,而不是使用常规响应。
重定向的相应内容是URL而不是html页面(重定向响应)。浏览器收到POST消息返回的响应时,会向重定向的 URL 发起 GET 请求,显示页面的内容。这个页面的加载可能要多花几微秒,因为要先把第二个请求发给服务器。这个技巧称为Post/重定向/Get 模式。
但这种方法会带来另一个问题。程序处理 POST 请求时,使用 form.name.data 获取用户输入的名字,可是一旦这个请求结束,数据也就丢失了。
程序可以把数据存储在用户会话中,在请求之间“记住”数据。它是请求上下文中的变量session
from flask import Flask, render_template, session, redirect, url_for
@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'))
Flash消息
需求用户提交了有一项错误的登录表单后,服务器发回的响应重新渲染了登录表单,并在表单上面显示一个消息,提示用户用户名或密码错误。
这种需求可以使用Flask的核心特性Flash实现。
from flask import Flask, render_template, session, redirect, url_for, flash
@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'))
对应地,在渲染模板中添加渲染Flash消息的模块
% block content %
<div class="container">
<!--在模板中使用循环是因为在之前的请求循环中每次调用 flash() 函数时都会生成一个消息,
所以可能有多个消息在排队等待显示。 get_flashed_messages() 函数获取的消息在下次调
用时不会再次返回,因此 Flash 消息只显示一次,然后就消失了。-->
% for message in get_flashed_messages() %
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
message
</div>
% endfor %
% block page_content % % endblock %
</div>
% endblock %
以上是关于flask学习笔记(-Web 表单)的主要内容,如果未能解决你的问题,请参考以下文章
Flask之旅《Flask Web开发:基于Python的Web应用开发实战》学习笔记