flask 中current_app._get_current_object()与current_app区别

在Flask异步发送邮件的场景中,使用current_app._get_current_object()而非current_app的原因在于current_app是一个线程本地代理。current_app._get_current_object()用于获取实际的对象实例,确保在多线程环境下能正确获取当前线程的Flask应用实例。如果不使用此方法,在新开的线程中,current_app将无法正确返回对象,因为LocalProxy设计为根据线程返回相应对象。

在学习flask开发,书中一段异步发送邮件的代码是这样写的:

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


def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)


def send_email(to, subject, template, **kwargs):
    app = current_app._get_current_object()
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    thr = Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return thr

在send_mail函数中,程序使用了current_app._get_current_object()赋值给app作为当前程序的实例。此处为什么不直接使用current_app呢?

flask官方文档中是这样解释这个方法_get_current_object()的:

Return the current object. This is useful if you want the real object behind the proxy at a time for performance reasons or because you want to pass the object into a different context.

这个问题的关键在倒数的第三句:
thr = Thread(target=send_async_email, args=[app, msg])

因为这里开了一个单独的线程,也许你会奇怪了,凭什么开了一个线程就不能使用 current_app 了?对!就是开了一个线程就不能使用 current_app。原因在于 current_app 的实现。

current_appFlask 是一个代理,如果你看 Flask 源码的话会发现其实它外部包裹的是这样的:
源码地址 line: 48-58

def _find_app():
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
    return top.app

...

current_app = LocalProxy(_find_app)

这个 LocalProxy 就不展开讲了,但是我可以告诉你这个LocalProxy 的作用就是可以根据线程/协程返回对应当前协程/线程的对象,也就是说

  • 线程 A 往 LocalProxy 中塞入 A

  • 线程 B 往 LocalProxy 中塞入 B

无论在是什么地方,

  • 线程 A 永远取到得是 A,线程 B 取到得永远是 B

这就是在 Flask 中可以在代码中直接使用 requestcurrent_app 这样的变量的底层原因。

所以,答案来了,因为这里开了一个新线程,如果你不穿真实对象过去,那么你在线程里面使用 current_app 将获取不到对象,因为他没有 flask 上下文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值