昨日回顾
1 @app.before_first_request,再项目启动后接收到的第一个请求,会执行before_first_request,他再@app.before_request之前执行。他也可以有多个,谁先注册谁先执行。无论有没有返回值,后面都会执行。
2 @app.before_request,再执行响应函数之前执行,他可以有多个,如果有多个谁先注册谁先执行,但是只要有一个有返回值,后面的before_request都会不执行,且响应函数也不执行。如果没有都befor_request返回值,那所有的before_request都会执行,且响应函数也会执行。
3 @app.after_request,再执行befor_request和响应之后执行,他可以有多个,如果有多个谁先注册谁后执行。被after_request装饰的函数,必须接收响应,且必须把响应对象返回。对于@pp.before_request有没有返回值,@app.after_request都会执行。
4@app.teardown_request,用来捕获错误,无论有没有错误都会执行。如果没有错误接收的错误就是none,如果有错误就会接收到错误。但是他不能处理错误。
5@app.errorhandler(500),用来捕获错误,捕获哪种错误,必须把错误的状态码传入到errorhandle中,如果没有错误就不会执行,如果有错误就能处理错误,给用户良好的体验。
6 @app.template_global(),相当于django中的标签,只要定义它,就可以再不把函数对象传递模板的情况下,再模板中直接使用。用法:{{函数名()}}
7 @app.template_filter(),相当于django中的过滤器,它使用和django中的过滤一样的用,但是它可以接收多个参数,无论是几个。用法:{{要过滤的值|函数名(参数)}}
local对象补充
import time
from threading import Thread,local,get_ident
#####这是使用local对象
# a = local()
# #
# # def task(arg):
# # a.value = arg
# #
# # time.sleep(1)
# #
# # print(a.value)
#####用函数的形式来模拟local
# storage = {}
# def set(k,v):
# # 获取线程id
# ident = get_ident()
# if ident in storage:
# storage[ident][k]=v
# else:
# storage[ident] = {k:v}
#
# def get(k):
# ident = get_ident()
# return storage[ident][k]
#
# def task(arg):
# set('val',arg)
# time.sleep(1)
# v = get("val")
# print(v)
#面向对象版1
# class Local:
# storage ={}
# def set(self,k,v):
# ident = get_ident()
# if ident in Local.storage:
# Local.storage[ident][k] = v
# else:
# Local.storage[ident] = {k:v}
#
# def get(self,k):
# ident = get_ident()
# return Local.storage[ident][k]
#
# obj = Local()
# def task(arg):
# obj.set("val",arg)
# time.sleep(1)
# v = obj.get("val")
# print(v)
# #面向对象的setattr,getattr版
# class Local:
# storage ={}
# def __setattr__(self,k,v):
# ident = get_ident()
# if ident in Local.storage:
# Local.storage[ident][k] = v
# else:
# Local.storage[ident] = {k:v}
#
# def __getattr__(self,k):
# ident = get_ident()
# return Local.storage[ident][k]
# obj = Local()
# # def task(arg):
# # obj.val=arg
# # time.sleep(1)
# # print(obj.val)
# 面向对象,将storage变成对象的属性
class Local(object):
def __init__(self):
#防止getattr递归
object.__setattr__(self,"storage",{})
#self.storage = {}
def __setattr__(self,k,v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k:v}
def __getattr__(self,k):
ident = get_ident()
return self.storage[ident][k]
obj = Local()
def task(arg):
obj.val=arg
time.sleep(1)
print(obj.val)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()
请求上下文
golbal文件,生成这些对象
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
每一次有请求都会执行app.wsig_app(environ, start_response)
app.wsig_app源码:
def wsgi_app(self, environ, start_response):
# RequestContext的对象,其中包含当前请求的东西。
ctx = self.request_context(environ)
error = None
try:
try:
#RequestContext的对象,ctx.push,就执行是RequestContext对象的push方法
#ctx放入local中
ctx.push()
#请求扩展以及响应函数
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
ctx = self.request_context(environ)做了什么?ctx=RequestContext的对象,里面有请求相关等所有东西:
# 1 我们self.request_context(environ)执行是:所以ctx是RequestContext(self, environ)的返回值:
def request_context(self, environ):
#等一下返回的ctx就是RequestContext()执行的结果。
return RequestContext(self, environ)
#2 RequestContext(self, environ)的执行结果是什么?是RequestContext的对象,这个对象中包含了reuqest等信息
class RequestContext(object):
#app, environ,ctx,就是RequestContext的对象,
def __init__(self, app, environ, request=None, session=None):
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
ctx.push(),这里的ctx,是RequestContext的对象,
#1 ctx.push方法就执行RequestContext的对象的push方法:
#源码:
def push(self):
#当前的self是RequestContext的对象,也就是ctx,
_request_ctx_stack.push(self)
#2 _request_ctx_stack,我们发现它是全局LocalStack()的对象。
#_request_ctx_stack.push(self)就是执行LocalStack中的push方法,并且把ctx传给了#_request_ctx_stack.push的push方法。self=ctx
#LocalStack中的push源码:
def push(self, obj):
rv = getattr(self._local, "stack", None)
if rv is None:
#storage[线程,协程id]["stack"] = []
self._local.stack = rv = []
rv.append(obj)
return rv
#上述代码中的self._local是Local对象,用来保证数据安全。
#当代码执行self._local.stack = rv = [],再Local对象中的存储结构是:storage[线程,协程id]["stack"] = []
# rv.append(obj),把storage[线程,协程id]["stack"] = [obj],又由于obj=ctx,就算就是把ctx放入到Local对象中。结构如下Local().storage[线程,协程id]["stack"] = [ctx]
response = self.full_dispatch_request()
#1
#这句话我们执行是请扩展与响应函数
#再响应函数和请求扩展中就可以使用request,它是如果和实现的呢?
from flask import Flask,request,session
app = Flask(__name__)
def index():
print(request.method)
print(session)
return "ok"
#比如上面代码中request.method,是如何拿到请求相关的内容呢?
#2
#我们点进去看request是什么?
request = LocalProxy(partial(_lookup_req_object, "request"))
#我们发现request就是 LocalProxy的对象。
#那我们再LocalProxy应该能找到method属性,但是发现没有,既然没有,它就一定写了__getattr__
#我们看__getattr__的源码:
def __getattr__(self, name):
#request.method,现在的name就是method
if name == "__members__":
return dir(self._get_current_object())
#现在的name是method,self._get_current_object()执行结果就偏函数的执行结果
#偏函数的执行结果中来获取method
#偏函数的执行结果就是request.
#etattr(request, method)
return getattr(self._get_current_object(), name)
#3
#我们再看看_get_current_object()它的执行结果是什么?
#self._get_current_object()的源码:
def _get_current_object(self):
return self.__local()
#上面的self._get_current_object()执行结果就是self.__local()的执行结果
# 4
#self.__local是什么?
#我们发现这个self.__local是实例化的时候传递的,也就local,代码如下
def __init__(self, local, name=None):
#self.__local= _LocalProxy__local=local = partial(_lookup_req_object, "request")
#self.__local设置为隐藏属性,
object.__setattr__(self, "_LocalProxy__local", local)
# self.__local=local
#local是实例化的时候传递的。我们实例化这个 LocalProxy(partial(_lookup_req_object, "request"))
# 我们self._get_current_object=self.__local=local=partial(_lookup_req_object, "request")
#5
#那最终我们明白了:
def __getattr__(self, name):
#request.method,现在的name就是method
if name == "__members__":
return dir(self._get_current_object())
return getattr(self._get_current_object(), name)
#self._get_current_object() 执行结果,就partial(_lookup_req_object, "request")的执行结果。
#就是ctx.request,所以getattr(self._get_current_object(), name)相当于getattr(ctx.request, method)
#6
#partial(_lookup_req_object, "request")()执行的结果
#_lookup_req_object的代码如下:
def _lookup_req_object(name):
#这里的name,是"request"
top = _request_ctx_stack.top
#top是谁?是ctx.
if top is None:
raise RuntimeError(_request_ctx_err_msg)
#top里面找request,也就是top= ctx--》ctx里面找request.
return getattr(top, name)
# 7
#又因为_request_ctx_stack是LocalStack()的对象,所以 _request_ctx_stack.top就是执行LocalStack()的对象中的top:
#_request_ctx_stack.top的源码:
@property
def top(self):
try:
# storage[线程,协程id]["stack"] = [ctx]
#现在top的retrun值就ctx
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
#代码中的self._local是Local对象,是我们存ctx的时候的Local对象。