Loading

flask的session的使用和原理、闪现、蓝图、G对象、flask-session的使用

1 session的使用和原理

1.1 session执行原理

1.2 flask的session源码分析

# app.session_interface---> 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,
        )

2 闪现

# flash 翻译过来的
# 假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
	-本质其实就是在a页面,把错误信息放到了某个位置,在b页面把错误取出来
    
# 在一次请求中,把一些数据放在闪现中,下次请求就可以从闪现中取出来,取一次就没了(使用分类也是这样)

# 本质就是放到session中了
#使用:
	-放值
    	-flash(err)
        -flash(err,category='lqz')
    -取值
    	-get_flashed_messages()
        -err = get_flashed_messages(category_filter=['lqz'])
        
        
        
 # 等同于djagno的message框架

3 请求扩展

# flask的请求扩展,装饰器,可以完成请求来了,请求走了,出异常了,页面找不到。。执行该装饰器装饰的函数,

# before_request
	-return四件套,不继续往下走了,如果retrun None,继续走下一个请求扩展
	-请求来了,就会执行它
    -多个before_request,会从上往下依次执行
# after_request
	-必须返回response对象
    -请求走了,会执行它
    -多个after_request,从下往上依次执行
# before_first_request
	-项目启动后,第一次访问,会执行
    -返回None,会继续往下执行,返回四件套,就不继续往后走了
    
# teardown_request
	-无论程序是否出异常,都会触发它
    -记录错误日志
    -app.debug=False模式才行
    
# errorhandler
	-监听某个状态码,如果是这个状态码的错误,就会触发它的执行
    -可以返回四件套,统一返回格式
    
# template_global:标签
	# 定义
	@app.template_global()
        def sb(a1, a2):
            return a1 + a2
    # 模板中使用
    {{sb(1,2)}}
# 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一样

4 蓝图

# Blue_print 翻译过来的,作用是对目录进行划分

# 不使用蓝图来划分目录----》不太好,因为全局就一个app对象,导来导去,很容易出现循环导入的问题
    -templates
    -views
        -__init__.py
        -user.py
        -order.py
    -app.py
    
# 蓝图的使用步骤:
	1 实例化得到蓝图对象 ---可以传一些参数:account = Blueprint('account', __name__,templates,static)
    2 把蓝图对象在app中注册---》app.register_blueprint(account,制定前缀)
    3 使用蓝图对象,注册路由
    4 蓝图有自己的请求扩展--》app对象总的请求扩展,每个蓝图有自己的请求扩展
    
# 使用蓝图来做目录划分---》使用蓝图对象,取代app对象
	-小型项目:目录结构如下,只有一个app的项目
        -flask_pro               #项目名
            -pro_flask          # 文件夹
                -__init__.py    # 包的init文件
                -static          #静态文件
                	-code.png
                -templates       #模板文件
                	-index.html
                -views           #视图函数写在里面
                    -account.py    #订单相关视图函数
                    -user.py     #用户相关视图函数
                    -blog.py     #博客相关视图函数
             -manage.py          # 项目的启动文件
    
    -大型项目:目录结构如下,多个app的项目

3.1 使用蓝图的小型项目

    -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()

4.2 使用蓝图的大型项目

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()

5 g对象

# flask 中有个 g 对象,在一次请求中,可以赋值,取值  :当次请求中得全局对象,在一次请求中放了值,后续就可以取出来
# 为什么不放在request中,为了防止值被覆盖掉

# g和session的区别?
	-g只对当次请求有效
    -session对这个人所有请求都有效
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))
    print(type(request))
    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)

6 flask-session的使用

# session默认以cookie的形式放到浏览中,我们想把session,放到服务端保存(redis中,mysql中。。。)
# 只需要写一个类,写open_session和save_session方法


# 使用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)---》包一下的写法
from flask import Flask, g, request,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)

posted @ 2022-08-14 14:20  香菜根  阅读(131)  评论(0)    收藏  举报