Flask篇:session的使用和原理、闪现、请求拓展、蓝图、g对象、flask-session
一、session的使用和原理
1.1 session执行原理
用户第一次请求后,将产生的状态信息保存在session中,这时可以把session当做一个容器,它保存了正在使用的所有用户的状态信息;这段状态信息分配了一个唯一的标识符用来标识用户的身份,将其保存在响应对象的cookie中;当第二次请求时,解析cookie中的标识符,拿到标识符后去session找到对应的用户的信息。
1.2 简单使用
from flask import Flask,session
app = Flask(__name__)
@app.route('/test1/')
def test():
session['name'] = 'xiaoming'
return 'OK'
if __name__ == '__main__':
app.run(host='127.0.0.1', port=80, debug=True)
1.3 flask的session源码分析
# 1.Flask源码中process_response
def process_response(self, response: Response) -> Response:
......
if not self.session_interface.is_null_session(ctx.session):
self.session_interface.save_session(self, ctx.session, response)
return response
# 2.session_interface是SecureCookieSessionInterface()类的对象
session_interface: SessionInterface = SecureCookieSessionInterface()
# 3.SecureCookieSessionInterface()类有两个方法
-open_session:请求来了,从cookie中取出字符串,把字符串反序列化成session对象
-save_session:请求走,把session对象,序列化成字符串,放到cookie中
# open_session
def open_session(self, app, request):
s = self.get_signing_serializer(app)
if s is None:
return None
val = request.cookies.get(app.session_cookie_name)
if not val:
return self.session_class()
max_age = total_seconds(app.permanent_session_lifetime)
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
# save_session
def save_session(self, app, session, response):
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
if not session:
if session.modified:
response.delete_cookie(
app.session_cookie_name, domain=domain, path=path
)
return
if session.accessed:
response.vary.add("Cookie")
if not self.should_set_cookie(app, session):
return
httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
expires = self.get_expiration_time(app, session)
val = self.get_signing_serializer(app).dumps(dict(session))
response.set_cookie(
app.session_cookie_name,
val,
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)
二、flash(闪现)
1.闪现的含义
flash音译过来的结果,可以在一个请求结束后记录信息,然后在下一次请求中展示。
# 假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
-本质其实就是在a页面,把错误信息放到了某个位置,在b页面把错误取出来
2.闪现的使用
-放值
flash(err)
flash(err,category='lqz') # category参数可以将信息进行分类
-取值
get_flashed_messages()
err = get_flashed_messages(category_filter=['lqz']) # category_filter过滤分类信息
3.闪现的特点
在一次请求中,把一些数据放在闪现中,下次请求就可以从闪现中取出来,取一次就没了(使用分类也是这样)
4.闪现的本质
闪现所记录的信息实际上是存在session中的,但是只能取一次,均在flash(存)和get_flashed_messages(取)的源码中有所体现
三、Flask请求拓展(装饰器)
1.作用
类似于django的中间件,不同的装饰器可以在请求的不同阶段进行拦截和操作
2.使用
2.1 before_request
from flask import Flask
app = Flask(__name__)
# @app.before_request
-return四件套,不继续往下走了,如果retrun None,继续走下一个请求扩展
-请求来了,就会执行它
-多个before_request,会从上往下依次执行
# 示例:
@app.before_request # 类似于,django的中间件的process_request,黑白名单机制
def before1():
# 所有人都不允许访问index
if request.path == '/':
return '不允许访问index' #return四件套,不继续往下走了,如果retrun None,继续走下一个请求扩展
print('before_request1111')
@app.before_request
def before2():
print('before_request2222')
2.2 after_request
# @app.after_request
-必须返回response对象
-请求走了,会执行它
-多个after_request,从下往上依次执行
# 示例:
@app.after_request
def after1(response):
print('after11')
print(response)
return response # 响应对象
@app.after_request
def after1(response):
print('after2222')
return response # 响应对象
2.3 before_first_request
# @app.before_first_request
-项目启动后,第一次访问,会执行
-返回None,会继续往下执行,返回四件套,就不继续往后走了
# 示例:
@app.before_first_request
def first():
print('我的第一次')
2.4 teardown_request
# @app.teardown_request
-无论程序是否出异常,都会触发它
-记录错误日志
-注意,只有app.debug=False模式才行
# 示例:
@app.teardown_request
def tear_down(e):
print(e) # 如果有错,e就是错误对象,如果没错,e就是空的
print('teardown_request')
# 没法返回统一的页面,四件套不能用
2.5 errorhandler
# @app.errorhandler
-监听某个状态码,如果是这个状态码的错误,就会触发它的执行
-可以返回四件套,统一返回格式
# 示例:
@app.errorhandler(404)
def errorhandl(arg):
print('页面没找到')
print(arg)
return render_template('404.html')
@app.errorhandler(500)
def errorhandl(arg):
print(arg)
return jsonify({'code': 999, 'msg': '请联系系统管理员'})
2.6 template_global
# @app.template_global:标签
# 定义
@app.template_global()
def sb(a1, a2):
return a1 + a2
# 模板中使用
{{sb(1,2)}}
2.7 template_filter
# @app.template_filter:过滤器
# 定义
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
# 模板中使用
{{ 1|db(2,3)}}
总结:
1 重点掌握before_request和after_request,
2 注意有多个的情况,执行顺序
3 before_request请求拦截后(也就是有return值),response所有都执行 ---》django一样
四、蓝图
1.蓝图的作用
在进行flask开发的时候,需要按照不同的封装对象进行开发。比如我们在开发电影网站,可以按照电影的url,用户的url,评论的url来进行开发,避免了将整个url都放入一个文件中,此时我们就需要使用到flask中的蓝图
2.不使用蓝图的目录
缺点
全局就一个app对象,导来导去,很容易出现循环导入的问题
-templates
-views
-__init__.py
-user.py
-order.py
-app.py
3.使用蓝图
3.1 使用步骤
(1) 实例化得到蓝图对象 ---可以传一些参数:account = Blueprint('account', __name__,templates,static)
(2) 把蓝图对象在app中注册---》app.register_blueprint(account,制定前缀)
(3) 使用蓝图对象,注册路由
(4) 蓝图有自己的请求扩展--》app对象总的请求扩展,每个蓝图有自己的请求扩展
3.2 使用蓝图小型项目目录划分
-flask_pro #项目名
-pro_flask # 文件夹
-__init__.py # 包的init文件
-static #静态文件
-code.png
-templates #模板文件
-index.html
-views #视图函数写在里面
-account.py #订单相关视图函数
-blog.py #博客相关视图函数
-manage.py # 项目的启动文件
pro_flask/init.py
from flask import Flask
app = Flask(__name__,template_folder='templates',static_folder='statics',static_url_path='/static')
from .views.account import account
from .views.blog import blog
# 注册3个蓝图,把他们注册进app中
app.register_blueprint(account)
app.register_blueprint(blog)
pro_flask/views/account.py
from flask import Blueprint
from flask import render_template
# 实例化得到蓝图对象
account = Blueprint('account', __name__)
@account.route('/login.html', methods=['GET', "POST"])
def login():
return render_template('login.html')
pro_flask/views/blog.py
from flask import Blueprint, render_template,request
blog = Blueprint('blog', __name__)
@blog.route('/get_blog')
def get_blog():
print(request.path)
return render_template('blog.html')
manage.py
from pro_flask import app
if __name__ == '__main__':
app.run()
3.3 使用蓝图大型项目目录划分
pro_flask # 项目名
-pro_flask #包名
-admin #admin app的名字
-static #app自己的静态文件
-templates #app自己的模板文件
-__init__.py #包的init
-views.py #app自己的视图函数
-web #web app的名字
-static #app自己的静态文件
-templates #app自己的模板文件
-__init__.py #包的init
-views.py #app自己的视图函数
-__init__.py
-run.py
pro_flask/admin/init.py
from flask import Blueprint
# 第一步:初始化蓝图
admin = Blueprint(
'admin',
__name__,
template_folder='templates', # 指定该蓝图对象自己的模板文件路径
static_folder='static' # 指定该蓝图对象自己的静态文件路径
)
from . import views
pro_flask/admin/views.py
from . import admin
from flask import render_template
@admin.before_request
def before():
print('admin 的 before')
# 第三步:使用蓝图注册路由
@admin.route('/index')
def index():
return render_template('admin.html')
pro_flask/web/init.py
from flask import Blueprint
web = Blueprint(
'web',
__name__,
template_folder='templates',
static_folder='static'
)
from . import views
pro_flask/web/views.py
from . import web
@web.route('/index')
def index():
return 'Web.Index'
pro_flask/init.py
from flask import Flask
from .admin import admin
from .web import web
app = Flask(__name__)
app.debug = True
# 第二步:在app中注册蓝图
app.register_blueprint(admin, url_prefix='/admin') # url_prefix='/admin' 访问这个app的前缀,等同于include
app.register_blueprint(web)
run.py
from pro_flask import app
if __name__ == '__main__':
app.run()
五、g对象
5.1 什么是g对象
flask 中有个 g 对象,在一次请求中,可以赋值,取值;
g对象是当次请求中得全局对象,在一次请求中放了值,后续就可以取出来;
为什么不放在request中:为了防止值被覆盖掉;
5.2 g和session的区别
-g对象只对当次请求有效
-session对当前用户所有请求都有效
5.3 g对象的使用
from flask import Flask, g, request,session
app = Flask(__name__)
app.debug=True
@app.before_request
def before():
print(type(g)) # werkzeug.local.LocalProxy 代理模式
print(type(session)) # werkzeug.local.LocalProxy
print(type(request)) # werkzeug.local.LocalProxy
if request.path == '/':
# request.method='lqz'
g.name = 'lqz' # 放到g对象中
else:
# request.name = 'pyy'
g.name = 'pyy'
def add(a,b):
print(g.name)
# print('-----', request.name)
@app.route('/')
def index():
print(g.name)
# print('-----',request.name)
# add(1,2)
return 'hello'
@app.route('/home')
def home():
print(g.name)
return 'hello'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
六、flask-session
6.1 为什么使用flask-session
session默认以cookie的形式放到浏览中,我们想把session,放到服务端保存(redis中,mysql中。。。)
通过上文中的1.3,我们了解了flask中session的执行原理,因此我们只需要写一个类,写open_session和save_session方法,就可以对session的存取进行操作
6.2 flask-session的使用方式(源码分析可得)
from flask import Flask, session
app = Flask(__name__)
app.debug=True
app.secret_key='asdasdfasdf'
# 使用flask-session:方式一:
from flask_session import RedisSessionInterface
app.session_interface=RedisSessionInterface(redis=None,key_prefix='luffy_')
# 方式二:通用方案
from redis import Redis
from flask_session import Session
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_KEY_PREFIX'] = 'luffy'
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port='6379')
Session(app) #后面会经常见这种写法--->类(app)---》包一下的写法
@app.route('/set_session')
def set_session():
session['name']='lqz'
return '设置成功'
@app.route('/get_session')
def get_session():
print(session['name'])
return '获取成功'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)