flask入门(2)

引言

上一节我们留了一个思考题,就是request在啥时候从env中获得具体的参数呢?
在这里插入图片描述
大致流程是上面的流程,具体的代码如下:

### 伪代码
global request

class App:
	def __call__(env, start_response):
		# 根据url选择对应的函数,比如选的是A
		A()
		start_response()
		return 
		
    def A():
       print(request.name)
       
    def B():
       print(request.name)
       
app = App()
	
		
if __name__ == '__main__':
	web_server = WebServer(host, port, app)#可以是gunicorn或者werkzeug的server
	web_server.run()

根据代码可以看到在调用call函数的时候,request还是一个空值,所以一定要在调用A()之前把request赋值具体怎么赋值?

flask源码

def __call__(environ, start_response):
        ctx = self.request_context(environ)
        ctx.push()
        response = self.full_dispatch_request()
        return response(environ, start_response)

根据flask的源码可以看到,其实和我们的伪代码相比,response等效于伪代码中的call
在这里插入图片描述
换句话说,就是在我们的伪代码前加了三行,那么这三行不用看源码都知道目的是:第一从environ读取信息并且赋值给request, 第二是根据url选出要执行的函数,也就是选择A()还是B()
在这里插入图片描述

具体分析

始终带着上面分析出来的两个目的来看源码:

ctx
# 可以看出ctx是一个RequestContext类型,ctx是其一个对象
 def request_context(self, environ):
     return RequestContext(self, environ)
 
 class RequestContextdef push(self):
     top = _request_ctx_stack.top
     if top is not None and top.preserved:
         top.pop(top._preserved_exc)
     app_ctx = _app_ctx_stack.top
     if app_ctx is None or app_ctx.app != self.app:
         app_ctx = self.app.app_context()
         app_ctx.push()
         self._implicit_app_ctx_stack.append(app_ctx)
     else:
         self._implicit_app_ctx_stack.append(None)
     _request_ctx_stack.push(self)#把自己压入请求上下文栈

从上面的代码可以看到两个核心概念:_request_ctx_stack和_app_ctx_stack,这里可以直接告诉大家,这个两个对象是全局对象,这里就望文生义当做是个栈用来分别存请求上下文和应用上下文的,push函数首先是看看栈的顶部有没有RequestContext(请求上下文)的对象,理论来说是没有的,因为对于这个全局变量_request_ctx_stack我们到目前为止从来没有操作过,同理_app_ctx_stack也一样,由于app_ctx也是空的,所以就进入下面的代码。

app_ctx = self.app.app_context()
app_ctx.push()
|||
# 返回一个应用上下文
def app_context(self):
    return AppContext(self)
# 应用上下文的类定义和push函数
class AppContext(object):
    def push(self):
        self._refcnt += 1
        _app_ctx_stack.push(self)# 可以看到_app_ctx_stack压入一个应用上下文
        appcontext_pushed.send(self.app)

终上可以发现前两行代码主要做了两件事,就是生成一个请求上下文(ctx)和应用上下文(app_ctx),然后分别压入请求上下文栈(_request_ctx_stack)和应用上下文栈(_app_ctx_stack),可以注意到ctx的初始化用到了environ, 而app_ctx是在ctx的push函数中创建的,盲猜全局变量request一定和ctx有关系。接下来看看源码:

# context locals
def _lookup_req_object(name):
    top = _request_ctx_stack.top
    return getattr(top, name)
def _lookup_app_object(name):
    top = _app_ctx_stack.top
    return getattr(top, name)
def _find_app():
    top = _app_ctx_stack.top
    return top.app
_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"))
g = LocalProxy(partial(_lookup_app_object, "g"))

可以看到request的定义在这,其实就是找_request_ctx_stack的顶部对象,然后这个请求上下中的request的属性就是全局request,到目前为止我们终于理出了逻辑。

思考

为啥画蛇添足搞个_request_ctx_stack?我直接定义一个RequestContext全局变量a,都有请求的时候把ctx赋值给a, 用的时候request = a.request不就可以了吗?此外LocalStack,LocalProxy是啥?还有请求上下文可以理解,搞个应用上下文是干嘛滴?以上问题会在下一节一一解释,同时分析第三行代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值