本部分学习如何使用表单为用户发表动态和登录认证提供途径。处理web表单使用flask-wtf插件。
1、安装flask-wtf.
(microblog) D:\pythonProgram\PycharmProjects\microblog>pip install flask-wtf
Collecting flask-wtf
Downloading Flask_WTF-0.15.1-py2.py3-none-any.whl (13 kB)
Requirement already satisfied: itsdangerous in d:\pycharmprojects\flask\microblog\lib\site-packages (from flask-wtf) (2.0.1)
Requirement already satisfied: Flask in d:\pycharmprojects\flask\microblog\lib\site-packages (from flask-wtf) (2.0.1)
Collecting WTForms
Using cached WTForms-2.3.3-py2.py3-none-any.whl (169 kB)
Requirement already satisfied: Werkzeug>=2.0 in d:\pycharmprojects\flask\microblog\lib\site-packages (from Flask->flask-wtf) (2.0.1)
Requirement already satisfied: click>=7.1.2 in d:\pycharmprojects\flask\microblog\lib\site-packages (from Flask->flask-wtf) (8.0.1)
Requirement already satisfied: Jinja2>=3.0 in d:\pycharmprojects\flask\microblog\lib\site-packages (from Flask->flask-wtf) (3.0.1)
Requirement already satisfied: colorama in d:\pycharmprojects\flask\microblog\lib\site-packages (from click>=7.1.2->Flask->flask-wtf) (0.4.4)
Requirement already satisfied: MarkupSafe>=2.0 in d:\pycharmprojects\flask\microblog\lib\site-packages (from Jinja2>=3.0->Flask->flask-wtf) (2.0.1)
Installing collected packages: WTForms, flask-wtf
Successfully installed WTForms-2.3.3 flask-wtf-0.15.1
2、对程序进行配置。
Flask(也可能是Flask插件)为使用者提供了一些可自由配置的选项。你需要决定传入什么样的配置变量列表到框架中。有几种途径来为应用指定配置选项。最基本的解决方案是使用app.config对象,它是一个类似字典的对象,可以将配置以键值的方式存储其中。例如,你可以这样做:
app = Flask(__name__)
app.config['SECRET_KEY'] = 'you-will-never-guess'
# ... add more variables here as needed
配置和应用代码不应该处于同一个部分,而是使用稍微复杂点的结构,将配置保存到一个单独的文件中。使用类来存储配置变量,这个配置类存储到单独的Python模块,以保持良好的组织结构。下面就让你见识一下这个存储在顶级目录下,名为config.py的模块的配置类吧:
import os
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
拥有了这样一份配置文件,我还需要通知Flask读取并使用它。可以在生成Flask应用之后,利用app.config.from_object()方法来完成这个操作:
from flask import Flask
from config import Config
app = Flask(__name__)
app.config.from_object(Config)
from app import routes
可以使用app.config中的字典语法来访问配置项。 在下面的Python交互式会话中,你可以看到密钥的值:
app.config['SECRET_KEY']
'you-will-never-guess'
3、用户登录表单。
表单类的定义:Flask-WTF插件使用Python类来表示Web表单,表单类单独存储到名为app/forms.py的模块中。定义用户登录表单来做一个开始,它会要求用户输入username和password,并提供一个“remember me”的复选框和提交按钮:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember Me')
submit = SubmitField('Sign In')
表单模板:LoginForm类中定义的字段支持自渲染为HTML元素,把登录模板存储在文件app/templates/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) }}
</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 %}
表单视图:编写一个新的视图函数来渲染上面创建的模板。函数的逻辑只需创建一个form实例,并将其传入渲染模板的函数中即可,然后用/login URL来关联它。这个视图函数也存储到app/routes.py模块中,代码如下:
from flask import render_template
from app import app
from app.forms import LoginForm
# ...
@app.route('/login')
def login():
form = LoginForm()
return render_template('login.html', title='Sign In', form=form)
在基础模板templates/base.html的导航栏上添加登录的链接,以便访问:
<div>
Microblog:
<a href="/index">Home</a>
<a href="/login">Login</a>
</div>
接收表单数据:点击提交按钮,浏览器将显示“Method Not Allowed”错误。这是因为之前的登录视图功能到目前为止只完成了一半的工作。 它可以在网页上显示表单,但没有逻辑来处理用户提交的数据。Flask-WTF可以轻松完成这部分工作, 以下是视图函数的更新版本,它接受和验证用户提交的数据:
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
flash('Login requested for user {}, remember_me={}'.format(
form.username.data, form.remember_me.data))
return redirect('/index')
return render_template('login.html', title='Sign In', form=form)
当你调用flash()函数后,Flask会存储这个消息,但是却不会奇迹般地直接出现在页面上。模板需要将消息渲染到基础模板中,才能让所有派生出来的模板都能显示出来。更新后的基础模板代码如下:
<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>
完善字段验证。这是给username和password字段添加了验证描述性错误消息渲染逻辑之后的登录模板:
{% 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>
{% 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 %}
拥有验证器的字段都会用form.<field_name>.errors来渲染错误信息。 一个字段的验证错误信息结果是一个列表,因为字段可以附加多个验证器,并且多个验证器都可能会提供错误消息以显示给用户。
生成链接,用flask的url_for()函数名代替URL:
<div>
Microblog:
<a href="{{ url_for('index') }}">Home</a>
<a href="{{ url_for('login') }}">Login</a>
</div>
login()视图函数也做了相应变更:
from flask import render_template, flash, redirect, url_for
# ...
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
# ...
return redirect(url_for('index'))
# ...