加入收藏 | 设为首页 | 会员中心 | 我要投稿 财气旺网 - 财气网 (https://www.caiqiwang.com/)- AI开发硬件、专属主机、建站、CDN、云容器引擎!
当前位置: 首页 > 站长学院 > Asp教程 > 正文

chapter4 - Web表单

发布时间:2023-05-23 23:01:49 所属栏目:Asp教程 来源:转载
导读: 本书使用的是Flask-WTf扩展来处理Web表单,它是把一个独立的WTForms集成了在Flask程序中。可以使用pip安装:(venv) $ pip install flask-wtf
4.1 跨站请求伪造保护
默认情况下,Flask-WTF可

本书使用的是Flask-WTf扩展来处理Web表单,它是把一个独立的WTForms集成了在Flask程序中。可以使用pip安装:(venv) $ pip install flask-wtf

4.1 跨站请求伪造保护

默认情况下,Flask-WTF可以保护所有表单免受跨站请求伪造(Cross-Site Request Forgery, CSRF)的攻击。为了实现这个防护,Flask-WTf需要在程序中设置一个密钥,然后再使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。设置密钥的方法如下: hello.py

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'

为了安全起见,密钥是不应该硬编码到程序中的,而是要保存到环境变量中。到第7章会介绍

4.2 表单类

使用Flask-WTF时,每个web表单都继续自Form类。这个类中包含了常用HTML表单中的各种字段,还为这些字段设置了一些验证函数可供使用,用于验证表单的输入数据。 如下为一个简单的weg表单,包含了一个文本字段和一个提交按钮: hello.py

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

name是一个文本字段,submit是一个提交按钮,分别相当于HTML中的:



name使用的StringField方法的第一个参数是显示在页面中的提示信息,第二个参数是一个表单验证项,用validators=[]方法实现,该方法接收一个列表,可在列表中放置多个验证函数。 以下是WTForms支持的HTML标准字段:

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

以下是WTForms内建的验证函数:

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

以下是几个字段和验证函数的使用示例asp表单,完整的使用示例和说明可参考末尾处提供的文档。

from wtforms import PasswordField
pwd1 = PasswordField('请输入你的密码:', validators=[Required()])
pwd2 = PasswordField('确认密码:', validators=[Required(), EqualTo('pwd1', message="密码不匹配")])

首先要导入字段函数,不过为了方便整个表单的使用,也可以直接使用from wtforms.fields import *的方式导入所有可用表单字段。PasswordField()方法的第一个参数是提示信息,第二个参数是验证函数,值是由验证函数组成的列表,用Required()可以设置必填项,EqualTo()用于匹配两个表单的输入,EqualTo()函数的第一个参数是需要进行比对的字段名称,第二个参数是匹配失败的时候的提示信息

from wtforms import RadioField
radios = RadioField('sex', choices=[(1, 'one'), (2, 'two')])

与其它字段类似,第一个参数是名字,但目前还没有发现有什么用处,在前端也不显示。第二个参数就是单选按钮的各个选项,可以是元组类型组成的列表,元组的第一个参数是value的值,第二个参数是显示在页面前端的名字。如上代码在前端中是这样子的:

对,Jinja2默认地用两个div来分别显示这两个radio了,默认地在页面前端看到的就是一个在上一个在下

from wtforms import BooleanField
checkbox = BooleanField('one', default=True)

第一个参数是显示在页面的名字,第二个参数可设置是否默认选中,如果不设置或者为False,则不选中

4.3 把表单渲染成HTML

表单字段是可调用的,可以通过参数例如form传到模板中,然后可以在模板中生成一个简单的表单:

{{ form.hidden_tag() }} {{ form.name.label }} {{ form.name() }} {{ form.submit() }}

还可以把参数传入渲染字段的函数来改进表单的外观,传入的参数会被转换成字段的HTML属性。如下代码可以指定name字段的id属性:

{{ form.hidden_tag() }} {{ form.name.label }} {{ form.name(id='my-text-field') }} {{ form.submit() }}

当然其实Bootstrap已经为我们提供了一些表单样式,可以这样调用:

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

于是完整的表单代码如下: 修改 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 %}

4.4 在视图函数中处理表单

目前为止,表单在视图函数中定义了,而模板中也对表单数据进行了渲染,还没有把数据发送到模板,因此需要修改视图函数: 修改 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)

在app.route修饰器中添加了method参数,使得index()视图函数可以处理GET和POST请求,如果没有添加的话,则只能处理GET请求,而表单提交通常应使用POST请求。 由于在表单类中为name字段设置了验证函数,所以如果验证通过,则validate_on_submit()方法会返回True,否则返回False。首次加载页面时,由于表单中没有数据,因此会返回False,直接加载表单,而在填写了表单数据并验证难过后,服务器会收到一个POST请求,就可以把输入的数据赋值给name变量并传到模板中进行渲染。form.name.data = ''可以在获取了表单输入数据后清空输入框。 而如果验证没通过的话,点击提交按钮时会收到一个错误提醒。

4.5 重定向和用户会话

在当前版本的hello.py中,如果在输入名字后提交表单,再刷新时,会被提示是否要重新发送已填写数据。在多数情况下,这并不是个理想的处理方式。 使用重定向就可以很好地解决这个问题。Flask中把重定向当成一种特定的响应,其响应的内容是URL。

但还有一个问题,就是当程序处理POST请求结束后,表单中获取到的用户输入数据就丢失了,如果使用重定向,就不能继续使用这些数据。此时,就要使用到用户会话,也就是第2章中提到的session。

使用了重定向和用户会话后的视图函数如下所示: 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'))

本程序使用了用户会话session来替代了前面的局部变量name,所以在两次请求之间也能够记住输入的数据。 如上代码中,如果表单输入正确,则会调用到redirect()函数。该函数用于生成HTTP重定向响应,其参数是重定向的URL,它的第一个参数必须指定端点名,即路由内部的名字,默认情况下路由端点是相应视图函数的名字。

4.6 Flash消息

Flash消息用于显示确认消息、警告或者错误提醒。

来自Flask文档中的Flash消息闪现说明:闪现系统的基本工作方式是:在且只在下一个请求中访问上一个请求结束时记录的消息。也就是说,当前看到的Flash消息,是上一次请求结束后设置的。

在hello.py文件中使用Flash消息:

from flask import redirect
from flask import flash
from flask import url_for
@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'))

在示例中,每次提交的名字会跟存储在session中的上一次提交的名字做比较,如果不一样,则会调用flash()函数,在发给客户端的下一个响应中显示消息。

flash()函数返回的消息需要被模板接收渲染:

修改 templates/base.html

{% block content %}
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %} {% block page_content %}{% endblock %}
{% endblock %}

在模板中使用循环是因为在之前的请求循环中每次调用flash()函数时,都会生成一个消息,所以可能会有多个消息在排除等待显示。get_flashed_message()函数获取的消息在下次调用时不会再次返回,其实这个函数获取到的消息是一个列表。

WTForms表单的具体使用可参数官方文档WTForms Documentation

Flash消息闪现的使用可参Flash文档-消息闪现

(编辑:财气旺网 - 财气网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章