利用Flask-WTF插件完成web表单

flask插件很丰富,不用自己重复造轮子。Web表单用来接收并响应用户的输入。

1、Flask-WTF插件

Flask为使用者提供了一些可自由配置的选项。你需要决定传入什么样的配置变量列表到Flask框架中。
安装Flask-WTF、WTForms插件:

pip install flask-WTF
pip install WTForms

2、配置

import os

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
#第一个项查找环境变量SECRET_KEY的值,第二个项是一个硬编码的字符串。首先检查环境变量中是否存在这个配置,找不到的情况下就使用硬编码字符串。在开发阶段,安全性要求较低,因此可以直接使用硬编码字符串。但是,当应用部署到生产服务器上的时候,我将设置一个独一无二且难以揣摩的环境变量,这样,服务器就拥有了一个别人未知的安全密钥了。

配置被定义为Config类中的属性, 一旦应用程序需要更多配置选项,直接依样画葫芦,附加到这个类上即可。
SECRET_KEY是我添加的唯一配置选项,对大多数Flask应用来说,它都是极其重要的。Flask及其一些扩展使用密钥的值作为加密密钥,用于生成签名或令牌。Flask-WTF插件使用它来保护网页表单免受名为Cross-Site Request Forgery或CSRF(发音为“seasurf”)的恶意攻击。

拥有了这样一份配置文件,我还需要通知Flask读取并使用它。可以在生成Flask应用(实例app)之后,利用app.config.from_object()方法来完成这个操作(在__init__.py脚本):

from flask import Flask
from config import Config#从配置文件中导入Config类

app = Flask(__name__)
app.config.from_object(Config)#让Flask实例读取我们设置的配置文件

from app import routes

3、用户登录表单

Flask-WTF插件使用Python类(FlaskForm)来表示Web表单。表单类只需将表单的字段定义为类属性即可。
表单类单独存储到名为app/forms.py的模块中:

#大多数Flask插件使用flask_ <name>命名约定来导入
#设置一个要求用户输入username和password,并提供一个“remember me”的复选框和提交按钮的表单
from flask_wtf import FlaskForm
#从flask_wtf插件中导入基类FlaskForm,flask_wtf本身不提供字段类型。
from wtforms import StringField,PasswordField,BooleanField,SubmitField
#从wtforms插件中导入4个表示表单字段的类,每个字段类都接受一个描述语作为第一个参数,并生成一个实例作为LoginForm的类属性。
from wtforms.validators import DataRequired
#可选参数validators用于验证输入字段是否符合预期。DataRequired验证器仅验证字段输入是否为空。更多的验证器将会在未来的表单中接触到。

class LoginForm(FlaskForm):
    username = StringField('Username',validators=[DataRequired()])#用StringField字段类定义表单中的Username字段,并验证输入是否为空。
    password = PasswordField('Password',validators=[DataRequired()])
    remember_me = BooleanField('Remember Me')#定义复选框
    submit = SubmitField('Sign In')#定义提交按钮

4、表单模板

把登录模板存储在文件*app/templates/login.html *中,代码如下:

#继承base.html模板
{% extends "base.html" %}

{% block content %}
#需要把form参数传入视图函数,form是LoginForm类的实例
    <h1>Sign In</h1>
    <form action="" method="post" novalidate>
    #HTML<form>元素被用作Web表单的容器。 表单的action属性告诉浏览器在提交用户在表单中输入的信息时应该请求的URL, 当action设置为空字符串时,表单将被提交给当前地址栏中的URL,即当前页面。 method属性指定了将表单提交给服务器时应该使用的HTTP请求方法。 默认情况下是用GET请求发送,但几乎在所有情况下,使用POST请求会提供更好的用户体验,因为这种类型的请求可以在请求的主体中提交表单数据, GET请求将表单字段添加到URL,会使浏览器地址栏变得混乱。
        {{ form.hidden_tag() }}
        #form.hidden_tag()模板参数生成了一个隐藏字段,其中包含一个用于保护表单免受CSRF攻击的token。对于保护表单,你需要做的所有事情就是在模板中包括这个隐藏的字段,并在Flask配置中定义SECRET_KEY变量,Flask-WTF会完成剩下的工作。
        <p>
        #只需在需要"字段标签"的地方加上{{ form.<field_name>.label }},需要这个"字段"的地方加上{{ form.<field_name>() }}。
            {{ form.username.label }}<br>
            {{ form.username(size=32) }}
        </p>
        <p>
            {{ form.password.label }}<br>
            {{ form.password(size=32) }}
        </p>
        <p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
        <p>{{ form.submit() }}</p>
    </form>
{% endblock %}

5、表单视图

编写一个新的视图函数来渲染上面创建的模板。(在基础模板templates/base.html的导航栏上添加登录的链接,以便访问)

<div>
    Microblog:
    <a href="/index">Home</a>
    <a href="/login">Login</a>
</div>

只需创建一个form实例,将其传入渲染模板即可,然后用"/login" URL来关联它。

@app.route('/')
@app.route('/index')
def index():#home页
    user = {'username':'GXS'}
    posts = [
        {
            'author': {'username': 'John'},
            'body': 'Beautiful day in Portland!'
        },
        {
            'author': {'username': 'Susan'},
            'body': 'The Avengers movie was so cool!'
        }
    ]
    return render_template('index.html',title = 'Home', user=user, posts = posts)

@app.route('/login')
def login():#登陆页
    form = LoginForm()
    return render_template('login.html', title='Sign In', form=form)

验证:
在这里插入图片描述
点击导航栏的Login:
在这里插入图片描述

6、接收表单数据

点击提交按钮,浏览器将显示“Method Not Allowed”错误。
目前只能在网页上显示表单,但没有逻辑来处理用户提交的数据。Flask-WTF可以轻松完成这部分工作,为了能接受和验证用户提交的数据,更新视图函数:

from flask import render_template, flash, redirect

@app.route('/login', methods=['GET', 'POST'])
#路由装饰器中的methods参数,定义浏览器向服务器提交表单数据时的请求方法。 它告诉Flask这个视图函数接受GET和POST请求,并覆盖了默认的GET。 HTTP协议规定,对于GET请求需要返回信息给客户端(本例中是浏览器)。 本应用的所有GET请求都是如此。 当浏览器向服务器提交表单数据时,通常会使用POST请求(实际上用GET请求也可以,但这不是推荐的做法)。之前的“Method Not Allowed”错误正是由于视图函数还未配置允许POST请求。 通过传入methods参数,你就能告诉Flask哪些请求方法可以被接受。
def login():
    form = LoginForm()
    #form.validate_on_submit()实例方法会执行form校验的工作,当浏览器发起GET请求的时候,它返回False,直接转到视图函数的最后一句来渲染模板。当用户在浏览器点击提交按钮后,浏览器会发送POST请求。form.validate_on_submit()就会获取到所有的数据,运行字段各自的验证器(在LoginForm类中有字段及validator的定义),全部通过之后就会返回True,这表示数据有效。一旦有任意一个字段未通过验证,这个实例方法就会返回False。
    #当form.validate_on_submit()返回True时,登录视图函数调用从Flask导入的两个新函数。
    if form.validate_on_submit():
        flash('Login requested for user {}, remember_me={}'.format(
            form.username.data, form.remember_me.data))
            #flash()函数是向用户显示消息的途径,许多应用使用这个技术来让用户知道某个动作是否成功。
        return redirect('/index')
        #redirect()函数指引浏览器自动重定向到它的参数所关联的URL
    return render_template('login.html', title='Sign In', form=form)

当你调用flash()函数后,Flask会存储这个消息,但是却不会直接出现在页面上。模板需要将消息渲染到基础模板中,才能让所有派生出来的模板都能显示出来。get_flashed_messages()是Flask中的一个函数,它返回用flash()注册过的消息列表。闪现消息的一个属性是,一旦通过get_flashed_messages()函数请求了一次,它们就会从消息列表中移除,所以在调用flash()函数后它们只会出现一次。

<html>
    <head>
        {% if title %}
        <title>{{ title }} - microblog</title>
        {% else %}
        <title>microblog</title>
        {% endif %}
    </head>
    <body>
        <div>
            Microblog:
            <a href="/index">Home</a>
            <a href="/login">Login</a>
        </div>
        <hr>
        {% with messages = get_flashed_messages() %}
        {% if messages %}
        <ul>
            {% for message in messages %}
            <li>{{ message }}</li>
            {% endfor %}
        </ul>
        {% endif %}
        {% endwith %}
        {% block content %}{% endblock %}
    </body>
</html>

在本例的视图函数login中,如果form.validate_on_submit()为True,则浏览器返回到redirect函数重定向的界面(本例中URL-’/index’),如果form.validate_on_submit()为False,则浏览器执行渲染login.html模板的操作,也即保留在login界面。

验证:
在这里插入图片描述
点击sign in之后,浏览器跳转到重定向的URL,并显示flash()提示符。
在这里插入图片描述

7、完善字符验证

表单字段的验证器可防止无效数据被接收到应用中。 应用处理无效表单输入的方式是重新显示表单,以便用户进行更正。下一个任务是通过在验证失败的每个字段旁边添加错误提示来改善用户体验。
实际上,表单验证器已经生成了这些描述性错误消息,所缺少的只是模板中的一些额外的逻辑来渲染它们。通常情况下,拥有验证器的字段都会用form.<field_name>.errors来渲染错误信息。
给username和password字段添加了验证描述性错误消息渲染逻辑之后的登录模板(login.html):

{% extends "base.html" %}

{% block content %}
    <h1>Sign In</h1>
    <form action="" method="post" novalidate>
        {{ form.hidden_tag() }}
        <p>
            {{ form.username.label }}<br>
            {{ form.username(size=32) }}<br>
            #在username和password字段之后添加for循环以便用红色字体来渲染验证器添加的错误信息。一个字段的验证错误信息结果是一个列表,因为字段可以附加多个验证器,并且多个验证器都可能会提供错误消息以显示给用户。
            {% for error in form.username.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.password.label }}<br>
            {{ form.password(size=32) }}<br>
            {% for error in form.password.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
        <p>{{ form.submit() }}</p>
    </form>
{% endblock %}

8、用url_for函数生成链接

讨论在模板(html)和重定向(redirect())中包含链接的妥当方法。
为了更好地管理链接,Flask提供了一个名为url_for()的函数,它使用URL到视图函数的内部映射关系来生成URL。例如,url_for(‘login’)返回/login,url_for(‘index’)返回/index。 url_for()的参数是endpoint名称,也就是视图函数的名字
使用函数名称而不是URL,有两个原因,一是URL比起视图函数名称变更的可能性更高,再者URL中包含动态组件,手动生成这些URL需要连接多个元素,枯燥乏味且容易出错,url_for()生成这种复杂的URL就方便许多。
从现在起,一旦
需要生成应用链接
,我就会使用url_for()。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值