from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表单类去渲染模板时需要用到 from forms import LoginForm app = Flask(__name__) WTF(app) # 在app上注册一个 WTF (所有的flask插件都必须进行注册) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET请求') liginForm = LoginForm() # 相当于java中利用无参构造器创建对象 return render_template('login.html', loginForm = liginForm) if request.method == 'POST': print('POST请求') loginForm = LoginForm(request.form) # 相当于java中利用有参构造器创建对象 print(loginForm) email = loginForm.email.data password = loginForm.password.data print("邮箱为:{},密码为:{}".format(email, password)) if loginForm.validate(): return render_template('index.html') else: return '表单验证失败,错误信息 -> ' + str(loginForm.errors) print(app.url_map) if __name__ == '__main__': app.run(debug=True)
1 一个请求路径怎么实现两个逻辑功能
实例:登录模块
进入登录页面和点击登录的请求路径都是一样的,只不过他们的请求方式不一样而已;这样我们在后台就只需要写一个视图函数来实现两个功能逻辑;进入登录页面的请求时GET请求,点击登录的请求是POST请求
2 后台如何利用一个视图函数实现不同的逻辑
根据请求方式不同执行不同的逻辑
利用 request 对象的属性来判断请求方式
request.method 返回值时请求方式(GET/POST/HEAD/OPTIONS)
2.1 编写一个简单的登录模块
2.1.1 要求
去往登录页面和点击登录的路径保持一致
后台利用一个视图函数处理去往登录页面和点击登录按钮的请求
如果是去往登录页面的请求就响应一个登录页面,如果是点击登录页面的请求就响应一个主页面并获取相关的登录数据
2.1.2 编写连个HTML文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>主页面</title> </head> <body> <h2>庠序科技主页面</h2> <hr /> <h4>Donot aim for your success if you really want it. Just stick to do what you love and believe in.</h4> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h2>庠序科技登录页面</h2> <hr /> <div> <form action="/login/" method="post"> <div> <label for="email">邮箱:</label><input type="text" id="email" name="email" /> </div> <div> <label for="password">密码:</label><input type="password" id="password" name="password" /> </div> <div> <button type="submit">登录</button> </div> </form> </div> </body> </html>
2.1.3 编写视图函数
from flask import Flask from flask import request from flask import render_template from werkzeug.datastructures import ImmutableMultiDict app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET请求') return render_template('login.html') if request.method == 'POST': print('POST请求') formData = request.form print(type(formData)) print(formData) email = formData.get('email', 'null') password = formData['password'] print("邮箱数据为:{},密码数据为:{}".format_map(email, password)) return render_template('index.html') print(app.url_map) if __name__ == '__main__': app.run(debug=True)
3 利用表单框架书写表单
3.1 导入表单框架
pip3 install -i https://pypi.doubanio.com/simple/ flask-wtf
3.2 编写表单类
from flask_wtf import FlaskForm from wtforms import Form from wtforms import StringField, BooleanField class LoginForm(Form): email = StringField() password = StringField() loginForm = LoginForm() # 实例化一个LoginForm对象 print(loginForm.password.label) print(loginForm.email.label) print(loginForm.email()) print(loginForm.data) print(loginForm.errors)
3.3 利用表单类去渲染模板
3.3.1 准备
从 flask_wtf 中导入 CSRFProtect
from flask_wtf import CSRFProtect as WTF # 利用表单类去渲染模板时需要用到
在 Flask对象 上注册一个 CSRFProtect
WTF(app) # 在app上注册一个 WTF (所有的flask插件都必须进行注册)
修改 Flask对象 的配置文件使得 WTF_CSRF_ENABLED 失效
app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效)
config.py 文件中的信息为 WTF_CSRF_ENABLED = False
详情请查看修改 Flask应用默认配置 先关内容
3.3.2 利用表单类渲染模板的步骤
》导入表单类
from forms import LoginForm
》创建一个表单类对象
liginForm = LoginForm()
》将这个表单对象传到模板中去
render_template('login.html', loginForm = liginForm)
》利用表单对象的相关方法去渲染模板
{{ loginForm.email.label }}:{{ loginForm.email() }}
注意:loginForm.email.label 和 loginForm.email() 都是python表达式,他们的返回值是一个字符串
from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表单类去渲染模板时需要用到 from forms import LoginForm app = Flask(__name__) WTF(app) # 在app上注册一个 WTF (所有的flask插件都必须进行注册) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET请求') liginForm = LoginForm() return render_template('login.html', loginForm = liginForm) print(app.url_map) if __name__ == '__main__': app.run(debug=True)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h2>庠序科技登录页面</h2> <hr /> <div> <form action="/login/" method="post"> <div> {{ loginForm.email.label }}:{{ loginForm.email() }} </div> <div> {{ loginForm.password.label }}:{{ loginForm.password() }} </div> <div> <button type="submit">登录</button> </div> </form> </div> </body> </html>
3.4 利用表单类获取数据
from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表单类去渲染模板时需要用到 from forms import LoginForm app = Flask(__name__) WTF(app) # 在app上注册一个 WTF (所有的flask插件都必须进行注册) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET请求') liginForm = LoginForm() # 相当于java中利用无参构造器创建对象 return render_template('login.html', loginForm = liginForm) if request.method == 'POST': print('POST请求') loginForm = LoginForm(request.form) # 相当于java中利用有参构造器创建对象 print(loginForm) email = loginForm.email.data password = loginForm.password.data print("邮箱为:{},密码为:{}".format(email, password)) return render_template('index.html') print(app.url_map) if __name__ == '__main__': app.run(debug=True)
3.5 如何利用表单框架去验证获取到的表单数据格式
3.5.1 在表单中为每个字段定义验证器
from flask_wtf import FlaskForm from wtforms import Form from wtforms import StringField, BooleanField # 导入用到的字段 from wtforms.validators import InputRequired, Length, Email # 导入用到的验证器 class LoginForm(FlaskForm): # 注意如果单独使用功能时要继承Form,如果在Flask框架中使用是要继承FlaskForm email = StringField( label='邮箱', # 修改渲染时的value值 validators=[ # 设定字段验证器 InputRequired('邮箱是必填项'), Email('邮箱格式错误') ] ) password = StringField( label='密码', validators=[ InputRequired('密码为必填项'), Length(6, 9, '密码长度为6到9') ] ) # loginForm = LoginForm() # 实例化一个LoginForm对象 # print(loginForm.password.label) # print(loginForm.email.label) # print(loginForm.email()) # print(loginForm.data) # print(loginForm.errors)
3.5.2 在视图函数中利用表单对象去验证表单对象中的数据是否有效
3.6 如何验证表单数据的合法性
前提:已经从前端获取到用户数据的邮箱和密码数据
思路:利用邮箱到数据库查询用户信息,如果有先关数据说明邮箱数据有效;通过邮箱查询到的用户信息中的密码数据和前端传过来的密码数据进行比较,如果相等就说明密码数据有效
3.6.1 模拟一个数据模型来充当数据库
class User: # 模拟用户类 def __init__(self, id, email, password, name): self.id = id self.email = email self.password = password self.name = name def check_password(self, password): return self.password == password users = [ # 模拟用户数据 User('1', 'fury@163.com', '111111', 'fury'), User('2', 'zeus@163.com', '222222', 'zeus'), User('3', 'warrior@163.com', '333333', 'warrior') ] # 根据用户ID去获取数据 def findById(userId): for user in users: if user.id == userId: return user else: return None # 根据用户邮箱去获取数据 def findByEmail(email): for user in users: if user.email == email: return user else: return None
3.6.2 调用相关方法判断表单数据是否有效
from flask import Flask from flask import request from flask import render_template from flask_wtf import CSRFProtect as WTF # 利用表单类去渲染模板时需要用到 from forms import LoginForm from models import findByEmail, findById app = Flask(__name__) WTF(app) # 在app上注册一个 WTF (所有的flask插件都必须进行注册) app.config.from_pyfile('config.py') # 修改app的配置文件(使 WTF_CSRF_ENABLED 失效) @app.route('/') def index(): return render_template('index.html') @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': print('GET请求') liginForm = LoginForm() # 相当于java中利用无参构造器创建对象 return render_template('login.html', loginForm = liginForm) if request.method == 'POST': print('POST请求') loginForm = LoginForm(request.form) # 相当于java中利用有参构造器创建对象 print(loginForm) if loginForm.validate(): email = loginForm.email.data password = loginForm.password.data print("邮箱为:{},密码为:{}".format(email, password)) user = findByEmail(email) if user: if user.check_password(password): return render_template('index.html') else: return '密码错误' else: return '该邮箱为注册' else: return '表单验证失败,错误信息 -> ' + str(loginForm.errors) print(app.url_map) if __name__ == '__main__': app.run(debug=True)
3.7 如何实现在用户登录成功后进入主页面,并显示:欢迎XXX
如果从前端获取到的登录数据判断为有效后,就将用户的名字信息添加到主页模板中,并渲染主页模板;如果用户没有登录就进入到主页面时会有登录和注册两个按钮
3.8 如何实现当用户成功登录并进入主页后,当客户端下次再次访问这也的时候服务器会知道该前端之前已经登录过
思路:用户数据验证成功后,就将唯一识别用户的信息存储到客户端的cookie中,当客户端下次访问服务器时机会携带这个cookie信息,服务器会根据这个cookie信息去判断该客户端是否登陆过,如果登陆过就进入主页显示“欢迎xxx”,否则就进入主页提示用户登录
注意:可以根据用户是否选择来“记住我”来设置cookie的有效时间
3.8.1 数据验证成功后就设置cookie
3.8.2 用户进入主页时会利用请求对象去获取cookie数据,如果获取到了就会在进入主页后显示为登录状态
注意:这里登录成功后仅仅会提示登录成功,并不会重定向到主页面去(故:需要手动修改路径才能到主页面去,这里有待改进)
3.9 这么把请求之前的逻辑单独罗列出来
思路:利用请求之前那个钩子 @app.before_request 这个钩子注释的函数会在每个请求之前执行
3.10 g对象的妙用
每个请求对象都会有一个g对象,可以向g对象添加属性,而且这g对象在这个请求路径下的所有函数共享这个g对象
3.11 如果用户在没有登录的情况下进入到主页面后怎么强制返回到登录页面
思路:写一个装饰器,该装饰器的功能是,如果进入主页面时通过cookie数据能够获取到用户数据就什么也不做,如果获取不到就重定向到登录页面
4 项目信息
4.1 项目结构
4.2 项目源代码
5 项目改进
获取源代码:点击前往