返回 首页

flask工作原理图


本文是初学时根据慕课网视频flask高级编程(鱼书)第五章, 第六章边学习边整理, 如有错误请指正, 谢谢.


一个请求进入flask框架后, flask会首先实例化一个Request Context封装了这次请求的相关信息(Request), 然后将请求上下文推入栈_request_ctx_stack(这是LocalStack的一个实例).

在RequestContext对象入栈之前会检查App Context对应栈栈顶的元素, 如果不是当前的app, 则会先将app推入. 因此如果在一个请求中使用(注意是在请求中)使用current_app是不需要手动push的.

current_app取得是_app_ctckx_stack 的栈顶元素中的app属性, 这个属性就是我们自己创建的app=Flask(__name__), 如果栈顶为空,则提示unbound, 同样的request指的是_request_ctx_stack的栈顶对应对象, 当一个请求结束的时候会出栈.

Local 与 LocalStack: werkzeug, LocalStack作为线程隔离对象栈的基本特性

其他

如果要在没有请求的情况下使用核心对象需要手动push和pop, 一个例子

ctx = app.app_context()
ctx.push() # 入栈, push是LocalStack中的方法
# 其他语句
ctx.pop()  # 出栈

以上代码等同于:

with app.app_context():
    # 其他语句

比如在异步发送邮件的时候:

from flask import render_template, current_app
from flask_mail import Message
from threading import Thread
from app.ext import mail

def async_send_mail(app, msg):
    #获取当前程序的上下文
    with app.app_context():
        mail.send(message=msg)


def send_mail(subject, to, tem, **kwargs):
    app = current_app._get_current_object()
    msg = Message(
        subject=subject, recipients=[to], sender=app.config['MAIL_USERNAME'])
    msg.html = render_template('email/' + tem + '.html', **kwargs)
    send = Thread(target=async_send_mail, args=(app, msg))
    send.start()

Local使用字典的方式实现的线程隔离, localStack封装了Local对象, 把Local对象作为自己的属性从而实现了线程隔离的栈结构 _request_ctx_stack和_app_ctx_stack 都是LocalStack的实例(在flask源码的globals.py末尾可以找到)

_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)

Flask: 核心对象, 承载了各种功能, 比如配置信息,注册路由的信息等 AppContext: 对核心对象的封装, 同时附加了额外的参数 Request: 请求信息, 比如url相关的参数 RequestContext: 对Request对象的封装


登录