from flask import Flask, current_app
app = Flask(__name__)
a = current_app
d = current_app.config['DEBUG']
flask中的经典错误
woring outside application context
,这个错误出现的原因在于flask的上下文机制flask中的上下文
应用上下文AppContext 对象 对核心对象Flask的封装
请求上下文RequestContext 对象 对Request的封装
当一个请求进入到框架之后,flask首先会实例化一个RequestContext对象,它封装了请求信息,flask是编写web应用的,所以我们要探讨flask是如何应用两个上下文的必须从一个请求进入flask框架开始
RequestContext会推入到_request_ctx_stack中,在入栈之前flask会去检查另外一个栈_app_ctx_stack中的栈顶元素,如果这个栈顶元素是空或者不是当前对象,那么flask会将AppContext推入到_app_ctx_stack中,然后才会将RequestContext推入_request_ctx_stack栈中
current_app和request永远是指向栈顶的,是运用了代理模式,在代理的时候,其实就是间接的在操作两个栈的栈顶元素
注意:Current_app是flask的核心对象,他是取了栈顶元素AppContext的app属性,request也是同样的道理,request也是Request属性
当请求结束是,两个栈中的元素会被弹出
from flask import Flask, current_app
app = Flask(__name__)
ctx = app.app_context() # 得到应用上下文的对象
ctx.push()
a = current_app
d = current_app.config['DEBUG']
ctx.pop()
在请求中不用手动的推入,flask已经帮我们推入了,当你写离线应用或者是单元测试的时候,需要手动推入
with语句
实现了上下文协议的对象使用with,这种对象我们通常称为上下文管理器
实现了
__enter__
,__exit__
上下文表达式必须返回一个上下文管理器,with后面的变量叫做上下文表达式
As后面的变量一定不是上下文管理器,而是上下文管理器的enter方法所返回的值
class A:
def __enter__(self):
a = 1
#return a
def __exit__(self):
b = 2
with A() as obj_a: # 这里的obj_a值为None,
# 这里要灵活一下,上下文表达式必须要返回一个上下文管理器并不一定要用函数的形式返回,实例化也可以
pass
- exit方法
class MyResource:
def __enter__(self):
print('connect to resource')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
回收资源,或者是处理异常,后面的三个参数是处理异常的时候使用
:param exc_type:异常类型
:param exc_val:异常的值
:param exc_tb:异常信息
:return: 默认返回的是False
True: with语句的外部不会再抛出异常
False: 当with语句执行完成之后,with的外部还会再次抛出异常
"""
if exc_tb:
print('process exception')
else:
print('no exception')
print('close resource connection')
return False
def query(self):
print('query data')
try:
with MyResource() as resource:
resource.query()
except Exception as ex:
pass
db.init_app(app)
db.create_all(app=app)
为什么要两次传入app呢,是因为在init_app中没有保存app这个变量,而是当做了一个临时参数使用的,所以
db.create_all
也需要找到一个appdb.create_all
怎么找到app呢,方案一,传入一个关键字参数app
方案二,current_app有值,也就是将应用上下文推入到栈中
with app.app_context():
db.create_all()
方案三,在构造函数中传入,
db = SQLAlchemy(app)
从源码中解决问题