Flask_0x03 Web表单

0x1 Flask-WTF

  git checkout 4a

  1.1 CSRF保护

    Flask-WTF可以处理表单

(venv) $ pip install flask-wtf

    Flask-WTF 使用程序设置的秘钥生成加密令牌,验证表单数据真伪实现CSRF保护

    设置密钥方法:hello.py:设置Flask-WTF

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

    app.config用来存储框架、扩展和程序本身的配置变量

    SECRET_KEY配置变量是通用密钥

  1.2 表单类

    WTForms:http://wtforms.readthedocs.io/en/latest/

    使用Flask-WTF时,每个Web表单都由一个继承自Form的类表示

    hello.py:Web表单,包括一个文本字段和一个提交按钮

from flask_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')

    StringField类表示type="text"的<input>元素
    StringField构造函数的参数validators指定一个由验证函数组成的列表,函数Required()确保提交不为空
    SubmitField类表示type="submit"的<input>元素

    WTForms支持的HTML标准字段

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

    WTForms验证函数

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

  1.3 表单渲染成HTML

    1.3.1 视图函数把NameForm实例通过参数form传入模板,在模板中可以生成一个简单的表单

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

    定义CSS样式

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

    1.3.2 可使用Bootstrap中预先定义好的表单样式渲染整个Flask-WTF

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

    wtf.quick_form()函数的参数为Flask-WTF表单对象

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

  1.4 视图函数中处理表单 

    视图函数index()不仅要渲染表单,还要接收表单中的数据

    hello.py:路由方法

@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)

    form = NameForm()视图函数创建一个NameForm类实例用于表示表单

    提交表单后,如果数据能被所有验证函数接受,validate_on_submit()返回True

    这个函数的返回值决定是重新渲染表单还是处理表单提交的数据

0x2 重定向和用户会话

    git checkout 4b

    重定向是一种特殊的响应,响应内容是URL,不是包含HTML代码的字符串

    用户会话保存在cookie中,使用设置的SECRET_KEY进行加密签名

    hello.py:重定向和用户会话

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'))

    局部变量name保存在用户会话中,session['name'],两次请求之间也能记住输入的值

    redirect()参数使用url_for(),url_for()保证URL和定义的路由兼容,而且修改路由名字后依然可用

    url_for()第一个参数必须是端点名,即路由内部的名字

    默认情况下,路由的端点是相应视图函数的名字

    示例中,处理根地址的视图函数是index(),因此传入url_for()函数的名字是index

0x3 Flash消息

    git checkout 4c

    服务器发回的响应渲染表单

    hello.py: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把get_flashed_messages()函数开放给模板

    templates/base.html:渲染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">&times;</button>
        {{ message }}
    </div>
    {% endfor %}

    {% block page_content %}{% endblock %}
  </div>
{% endblock %}

    在模板中使用循环是因为每次调用flash()函数时都会生成一个消息,所以可能有多个消息排队等待显示

 

posted @ 2017-01-24 22:49  Hxxxxx  阅读(310)  评论(0编辑  收藏  举报