web表单是web应用中最基本的构建要素,我们将通过表单来实现用户发帖和应用登录功能。
创建config.py:
CSRF_ENABLED = True #。CSRF_ENABLED配置启用了[跨站请求攻击保护],大部分情况下你都需要开启此功能,这能使你的应用更安全。
SECRET_KEY = 'you-will-never-guess' #SECRET_KEY设置当CSRF启用时有效,这将生成一个加密的token供表单验证使用,你要确保这个KEY足够复杂不会被简单推测。
用户登录表单
使用Flask-WTF创建的表单就像一个对象,需要从Form类继承子类。然后在这个子类中定义一些类的属性变量作为表单字段就可以了。
表单模板
<!-- extend from base layout -->
{% extends "base.html" %}
{% block content %}
<h1>Sign In</h1>
<form action="" method="post" name="login">
{{form.hidden_tag()}}
<p>
Please enter your OpenID:<br>
{{form.openid(size=80)}}<br>
</p>
<p>{{form.remember_me}} Remember Me</p>
<p><input type="submit" value="Sign In"></p>
</form>
{% endblock %}
它使用模板参数 {{ ... }} 来实例化表单字段,而表单字段又来源于我们刚刚定义的表单类,模板参数中使用了 form 这个名称。当我们使用视图函数引用表单类并渲染到模板时,我们要特别注意这个把表单类传递到模板的变量名。
我们在配置中开启了CSRF(跨站伪造请求)功能,模板参数 {{ form.hidden_tag() }} 会被替换成一个具有防止CSRF功能的隐藏表单字段。在开启了CSRF功能后,所有模板的表单中都需要添加这个模板参数。
表单视图
from flask import render_template, flash, redirect
from app import app
from forms import LoginForm
# index view function suppressed for brevity
@app.route('/login', methods = ['GET', 'POST'])
def login():
form = LoginForm()
return render_template('login.html',
title = 'Sign In',
form = form)
我们引入登录表单类,然后把它实例化到一个变量,最后再把这个变量传给模板。
从表单中接收数据
下面就是我们这个登录视图函数的新版本, 加入了表单数据验证和处理 。下面就是我们这个登录视图函数的新版本, 加入了表单数据验证和处理:
@app.route('/login', methods = ['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
flash('Login requested for OpenID="' + form.openid.data + '", remember_me=' + str(form.remember_me.data))
return redirect('//www.greatytc.com/index')
return render_template('login.html',
title = 'Sign In',
form = form)
validate_on_submit() 这个方法做了表单处理的所有工作。如果你在表单向用户提供数据时(举个栗子:用户在它之前修改了一下提交的数据) 时调用此方法,它会返回 False。
当 validate_on_submit() 方法返回 True 的时候,我们的视图函数又会调用两个新的函数。它们都是从Flask 中引入的,flash 函数用来在下一个打开的页面中显示定义的消息。我们现在用它用来做调试。因为我们现在还没有做用户登录模块, 所以只需要把用户提交上来的数据显示一下就行了。flash 函数非常有用,比如为用户的一些操作提供消息反馈。
flash 函数提供的消息不会自动出现在我们的网站页面中,所以我们需要做点事情让它在页面中显示出来。为了让我们所有页面都能有这项激动人心的功能,所以就把它添加到基础模板中吧, 下面是更新后的基础模板 :
<html>
<head>
{% if title %}
<title>{{title}} - microblog</title>
{% else %}
<title>microblog</title>
{% endif %}
</head>
<body>
<div>Microblog: <a href="//www.greatytc.com/index">Home</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>