利用pycharm学习flask(八)

本文内容:

1.跨站请求伪造保护
2.表单类
3.把表单渲染成HTML
4.在视图函数中处理表单

跨站请求伪造保护

Flask-WTF是一个扩展,可以帮助我们处理web表单,我们跟前面一样在pycharm中安装它。

默认情况下,Flask-WTF能保护所有表单免受跨站请求伪造的攻击。Flask-WTF需要程序设置一个密匙。Flask-WTF使用这个密匙生成加密令牌,再用令牌验证请求中表单数据的真伪。

修改hello.py:

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

其中app.config字典用来存储框架、扩展和程序本身的配置变量。使用标准的字典句法就能把配置值添加到app.config对象中。

表单类

使用Flask-WTF时,每个Web表单都由一个继承自Form的类表示。这个类定义表单中的一组字段,每个字段都用对象表示。字段对象可附属一个或多个验证函数。验证函数用来验证用户提交的输入值是否符合要求。

修改hello.py,定义表单类:

1
2
3
4
5
6
7
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import Required

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

这个表单中的字段都定义为类变量,类变量的值是相应字段类型的对象。NameForm表单中有一个名为name的文本字段和一个名为submit的提交按钮。StringField类表示属性为type=“text”的input元素。SubmitField类表示属性为type=”submit”的input元素。

WTForms支持的HTML标准字段

字段类型 说 明
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 一组指定类型的字段

WTForms验证函数

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

把表单渲染成HTML

Flask-Bootstrap 提供了一个非常高端的辅助函数,可以使用Bootstrap中预先定义好的表单样式渲染整个 Flask-WTF表单,而这些操作只需一次调用即可完成。使用Flask-Bootstrap,上述表单可使用下面的方式渲染:

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

import指令的使用方法和普通Python代码一样,允许导入模板中的元素并用在多个模板中。导入的bootstrap/wtf.html文件中定义了一个使用Bootstrap渲染 Falsk-WTF表单对象的辅助函数。wtf.quick_form() 函数的参数为Flask-WTF表单对象,使用Bootstrap的默认样式渲染传入的表单。

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

1
2
3
4
5
6
7
8
9
10
11
{% 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 %}

模板的内容区现在有两部分。第一部分是页面头部,显示欢迎消息。Jinja2中的条件语句格式为...。如果条件的计算结果为True,渲染if和else指令之间的值。如果计算结果为False,则渲染else和endif指令之间的值。在上述例子中,如果没有定义模板变量name,则渲染字符串”Hello,Stranger!”。内容区的第二部分使用wtf.quick_form()函数渲染NameForm对象。

###在视图函数中处理表单
视图函数index不仅要渲染表单,还要接收表单中的数据,修改hello.py如下:

1
2
3
4
5
6
7
8
@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',from=from,name=name)

其中app.route修饰器中添加的methods参数告诉flask在url映射中把这个视图函数注册为GET和POST请求的处理程序,如果没有这个参数,默认为GET请求。

局部变量name存储表单中的名字,如果没有输入就为NONE,创建了一个NameForm类实例用于表示表单。提交表单后,如果数据能被所有验证函数接受,那么validate_on_submit方法返回True,否则返回False。这个值决定是重新渲染表单还是处理表单提交的数据。

第一次访问时,服务器收到一个没有表单数据的GET请求,所以validate_on_submit返回False。if语句将被跳过,通过渲染模板处理请求,并传入表单对象和值为None的name变量作为参数。用户在浏览器中显示了一个表单。

提交表单后,服务器收到GET请求,validate_on_submit调用name字段上的Required验证函数。如果名字不为空,就通过。validate_on_submit返回True。用户输入的名字可以通过字段的data属性获取。

在if语句中,把名字复制给name,然后再把data属性设为空字符串,从而清空表单字段。最后一行调用render_template函数渲染模板,但这次参数name的值为表单中输入的名字,因此会显示一个针对该用户的欢迎消息。

坚持原创技术分享,您的支持将鼓励我继续创作!