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 一组指定类型的字段
验证函数 说 明
Email 验证电子邮件地址
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">

{{ myform.hidden_tag() }}

{{ 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">

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