在flask的ctx.py文件中
可以看到AppConext类和RequestContext类
在flask的global.py中,可以看到current_app、request、session和g都是LocalProxy对象
# context locals_request_ctx_stack = LocalStack()_app_ctx_stack = LocalStack()current_app = LocalProxy(_find_app) #_find_app是找到app核心对象request = LocalProxy(partial(_lookup_req_object, 'request')) #这里是找到request核心对象session = LocalProxy(partial(_lookup_req_object, 'session'))g = LocalProxy(partial(_lookup_app_object, 'g'))
原理
Threadlocal线程局部变量
例如request虽然是全局变量,但是不同的请求的request.args.get(‘field_name’)获取到的值是不同的。
/name?name=Tom
/name?name=Jack
request.args={
‘thread_a_name’:’Tom’,
‘thread_a_name’:’Jack’
}
因此,单独上下文时,需要使用with app.app_context和with app.request_context
都是当作全局变量使用,实际上是线程内部的全局变量。
上下文代表的是环境,即不同的线程。例如request虽然是全局变量,但是在不同的场景下是不一样的。
Flask 在分派请求之前激活(或推送)应用和请求上下文,请求处理完成后再将其删除。应
用上下文被推送后,就可以在当前线程中使用 current_app 和 g 变量。类似地,请求上下
文被推送后,就可以使用 request 和 session 变量。如果使用这些变量时没有激活应用上
下文或请求上下文,就会导致错误。

请求上下文
request
通过request 请求的属性或方法
应用上下文
是对Flask的封装
current_app
app代表的是app = Flask(name)的app
应用场景
例如在蓝图py中,需要获取app.config[‘xx’]的信息,那么操作方式可能是from main import app,但是主程序中也会导入蓝图文件,那么就会存在循环导入的问题,因此,使用全局变量current_app则可以解决这个问题。
例如app.py
from flask import Flaskdef create_app(Config):app = Flask(__name__)app.config.from_object(Config)return appclass DeConfig():SECRET_KEY = 'xxx000999'app = create_app(DeConfig)from bl import my_blapp.register_blueprint(my_bl, url_prefix='/bl/')if __name__ == '__main__':app.run()
/bl.init.py
from flask import Blueprint, current_appmy_bl = Blueprint(__name__, 'my_bl')@my_bl.route('/hi')def hi():return current_app.config['SECRET_KEY']
此时访问http://127.0.0.1:5000/bl/hi时,可以在页面上看到SECRET_KEY的值。
g
使用場景
在视图函数操作中,可能会调用到其他的函数,并且会传递参数。一个参数还好,但是参数一多就比较麻烦了。使用g可以解决这个问题。g可以作为一个容器存储相关的变量信息。
g起到的是临时存储的作用,每次请求后g都会被清空。
app_context
正常情况下无法直接调试时使用current_app和g,可以使用app_context帮助调试
from flask import Flaskapp = Flask(__name__)@app.route('/')def index():return '<h1>Hello World!</h1>'with app.app_context():print(current_app.xxx)
设置变量
读取变量
g.var_name
案例
认证机制
对于特定视图,可以提供强制要求用户登录的限制;【涉及到装饰器】
对于所有视图,无论是否强制要求用户登录,都可以在视图中尝试获取用户认证后的身份信息。【涉及到钩子】
路径:请求 — 请求钩子(尝试判断用户身份,对未登录用户不做处理,放行)用g对象保存用户身份信息
— 普通试图处理 /(强制登录视图—装饰器)
这里涉及到了两个装饰器,一个是路由装饰器,一个是视图函数的强制登录的装饰器,因为强制登陆的装饰器是要增加get_user_profile视图函数的功能,因此路由装饰器要在其外面。
from flask import Flask, abort, current_app, gapp = Flask(__name__)# 请求钩子(尝试判断用户身份,对未登录用户放行) 使用g对象保存用户信息@app.before_requestdef authentication():"""利用before_request请求钩子,在进入所有视图前先尝试判断用户身份"""# 可以使用cookie、session、jwt等鉴权# 如果用户已登陆,用户则有身份信息# g.user_id = '123'# 如果用户未登录,用户无身份信息g.user_id = None# 强制登陆的装饰器def login_required(func):def wrapper(*args, **kwargs):# 判断用户是否登陆了if g.user_id:return func(*args, **kwargs)else:abort(401)return wrapper@app.route('/')def index():return "Hello {}".format(g.user_id)@app.route('/profile')@login_requireddef get_user_profile():return "user profile page user_id = {}".format(g.user_id)if __name__ == '__main__':app.run(port=8000, debug=True)
如果user_id为None的话,此时访问http://127.0.0.1:8000/profile,结果为
