第三章
本节主要是制作一个会员注册页面,同时针对有些字段进行验证。如果提交数据都没有问题就是出现一个闪现消息:通知验证OK。
一、安装Flask-WTF模块
为了更高效的制作表单,引用一个瘦小的form包装器WTForms,现已有此功能的一个flask扩展包——flask-wtf。
pip install flask-wtf
二、配置
1、我们可以在初始化时添加配置:
init.py(两下划线不显示)
app = Flask(__name__)
app.config['SECRET_KEY'] = 'you-will-never-guess'
# ... add more variables here as needed
2、独立配置模块
在APP中,我们经常会用到一些参数配置。秉承先前独立原则,独立出来配置项,在等级目录中建立一个配置模块:config.py。
另外为了防止Cross-Site Request Forgery(跨站点伪造请求),需要秘钥控制。
import os
class Config(object):
#environ表示环境变量,
#二次元操作:当系统有环境变量时就取名为SECRET_KEY的环境变量,否则赋值'you-will-never-guess'
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
3、应用配置类对象
由于我们在前边的配置模块中定义了Config类,又怎么让flask识别并添加配置呢?
还好,模块中已有一个方法:app.config.from_object()
在app/init.py中导入模块:
from flask import Flask
from config import Config #导入刚才建立的Config模块
app = Flask(__name__)
app.config.from_object(Config) #第一个小写config是模块,第二个大写config模块中定义的Config类
三、用户登录表单
在web中,每一个表单是一个个tag。但是,在python中,是用一个个类来呈现表单。通过一个类类定义各个字段。
构建表单模块
app/forms.py:
#flask的扩展库一般是以flask_**来命名
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired
#请注意添加FlaskForm,否则在视图函数的validate_on_submit属性将不能被引用
class LoginForm(FlaskForm):
#各字段第一个参数值表示的是字段显示名称,DataRequired()用来验证数据是否为空
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember Me')
submit = SubmitField('Sign In')
四、表单模板
构建LoginForm模块:
app/templates/login.html
{% extends "base.html" %}
{% block content %}
<h1>Sign In</h1>
<form action="" method="post" novalidate> #action表示向何处发送表单数据,为空代表当前地址
{{ form.hidden_tag() }} #生成一个隐藏的字段,防止CSRF攻击,一般同秘钥一起使用
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }} #size:输入字段的宽度
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }} #size:输入字段的宽度
</p>
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
Tip:
1、{{ form.<field_name>.label }}:获取表单字段的属性值
2、{{ form.<field_name>() }}:括号内参数是给html元素添加属性值
3、{{form.<field_name>}}:获取表单字段
五、表单视图
增加login的视图函数
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)
六、获取表单数据
1、提交方式及表单数据验证
validate_on_submit():
a、如果浏览器是发送GET方式,返回False;
b、如果POST方式且各表单字段验证通过,则返回True。
from flask import render_template, flash, redirect
@app.route('/login', methods=['GET', 'POST']) #methods:访问请求方式
def login():
form = LoginForm()
if form.validate_on_submit(): #当浏览器传递的是Get方式时,validate_on_submit()返回False,如果Post方式时,所有字段如果验证通过方可返回True
flash('Login requested for user {}, remember_me={}'.format(
form.username.data, form.remember_me.data)) #flash生成一个提示闪现消息
return redirect('/index') # redirect:跳转页面
return render_template('login.html', title='Sign In', form=form)
2、Html设置闪现信息
虽然上边我们设置了flash信息,但是还不会显示出来。
其中遇到一个坑:{%…%}语法,如果在%符号前后加入空格的话,网页访问的时候,后台程序会报错,提示‘}’错误。
base.html中增添闪现信息,通过列表方式展示。
<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() %} #获取所有的闪现消息,list方式存储
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</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) }}<br>
{% for error in form.username.errors %} #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 %}
至此,运行flask后,最后的界面如下:
八、生成连接
在前边,我们共使用了两种连接方式。
其一:在导航栏模板中定义的导航项:
<div>
Microblog:
<a href="/index">Home</a>
<a href="/login">Login</a>
</div>
其二:在登录模板中使用的跳转操作:
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
# ...
return redirect('/index')
# ...
这种方式直接拼写连接地址,会存在一个问题:如果后期需要修改连接地址的时候,你就需要查找到代码文件再修改,随着网页量增多,维护起来就困难。
Flask自带了一个很好的函数url_for()来处理此种问题。
url_for():用于构建指定函数的URL,即把url映射到视图函数。
使用url_for()的两个优点:
a、url相比视图函数更可能会变动
b、url会带有一些动态的参数,如果手工拼写就会是很痛苦的。
url_for()的基本用法:
第一个参数是endpoint(URL的端点),即视图函数名称。
第二个参数是一些命名参数。
#通过视图函数映射
url_for(‘index’ name =’wang’,external=True) #第一个参数index是视图函数名,第二个参数自定义的参数(可以起到拼接的效果)。
#通过静态文件映射
url_for('static',filename='css/styles.css',_external=True) 得到的结果:http://localhost:5000/static/css/styles.css
上边两种连接方式的改进方式如下:
<div>
Microblog:
<a href="{{ url_for('index') }}">Home</a> #index是视图函数名称
<a href="{{ url_for('login') }}">Login</a> #login是视图函数名称
</div>
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')) #index是视图函数名称
# ...