### 导航
- [索引](# "总目录")
- [下一页](# "请求上下文") |
- [上一页](# "即插视图") |
- [Flask 0.10.1 文档](#) »
# 应用上下文
0.9 新版功能.
Flask 背后的设计理念之一就是,代码在执行时会处于两种不同的“状态”(states)。当 Flask 对象被实例化后在模块层次上应用便开始隐式地处于应用配置状态。一直到第一个请求还是到达这种状态才隐式地结束。当应用处于这个状态的时候,你可以认为下面的假设是成立的:
- 程序员可以安全地修改应用对象
- 目前还没有处理任何请求
- 你必须得有一个指向应用对象的引用来修改它。不会有某个神奇的代理变量指向你刚创建的或者正在修改的应用对象的
相反,到了第二个状态,在处理请求时,有一些其它的规则:
- 当一个请求激活时,上下文的本地对象( [flask.request](# "flask.request") 和其它对象等)指向当前的请求
- 你可以在任何时间里使用任何代码与这些对象通信
这里有一个第三种情况,有一点点差异。有时,你正在用类似请求处理时方式来与应用交互,即使并没有活动的请求。想象一下你用交互式 Python shell 与应用交互的情况,或是一个命令行应用的情况。
[current_app](# "flask.current_app") 上下文本地变量就是应用上下文驱动的。
### 应用上下文的作用
应用上下问存在的主要原因是,在过去,请求上下文被附加了一堆函数,但是又没有什么好的解决方案。因为 Flask 设计的支柱之一是你可以在一个 Python 进程中拥有多个应用。
那么代码如何找到“正确的”应用?在过去,我们推荐显式地到处传递应用,但是这会让我们在使用不是以这种理念设计的库时遇到问题。
解决上述问题的常用方法是使用后面将会提到的 [current_app](# "flask.current_app") 代理对象,它被绑定到当前请求的应用的引用。既然无论如何在没有请求时创建一个这样的请求上下文是一个没有必要的昂贵操作,应用上下文就被引入了。
### 创建应用上下文
有两种方式来创建应用上下文。第一种是隐式的:无论何时当一个请求上下文被压栈时,如果有必要的话一个应用上下文会被一起创建。由于这个原因,你可以忽略应用上下文的存在,除非你需要它。
第二种是显式地调用 [app_context()](# "flask.Flask.app_context") 方法:
~~~
from flask import Flask, current_app
app = Flask(__name__)
with app.app_context():
# within this block, current_app points to app.
print current_app.name
~~~
在配置了 SERVER_NAME 时,应用上下文也被用于 [url_for()](# "flask.url_for") 函数。这允许你在没有请求时生成 URL 。
### 应用上下文局部变量
应用上下文会在必要时被创建和销毁。它不会在线程间移动,并且也不会在不同的请求之间共享。正因为如此,它是一个存储数据库连接信息或是别的东西的最佳位置。内部的栈对象叫做 [flask._app_ctx_stack](# "flask._app_ctx_stack") 。扩展可以在最顶层自由地存储额外信息,想象一下它们用一个充分独特的名字在那里存储信息,而不是在 [flask.g](# "flask.g")对象里, [flask.g](# "flask.g") 是留给用户的代码用的。
更多详情见 [*Flask 扩展开发*](#) 。
### 上下文用法
上下文的一个典型应用场景就是用来缓存一些我们需要在发生请求之前或者要使用的资源。举个例子,比如数据库连接。当我们在应用上下文中来存储东西的时候你得选择一个唯一的名字,这是因为应用上下文为 Flask 应用和扩展所共享。
最常见的应用就是把资源的管理分成如下两个部分:
1. 一个缓存在上下文中的隐式资源
1. 当上下文被销毁时重新分配基础资源
通常来讲,这将会有一个 get_X() 函数来创建资源 X ,如果它还不存在的话。存在的话就直接返回它。另外还会有一个 teardown_X() 的回调函数用于销毁资源X 。
如下是我们刚刚提到的连接数据库的例子:
~~~
import sqlite3
from flask import g
def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = connect_to_database()
return db
@app.teardown_appcontext
def teardown_db(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()
~~~
当 get_db() 这个函数第一次被调用的时候数据库连接已经被建立了。为了使得看起来更隐式一点我们可以使用 [LocalProxy](http://werkzeug.pocoo.org/docs/local/#werkzeug.local.LocalProxy "(在 Werkzeug v0.10)") [http://werkzeug.pocoo.org/docs/local/#werkzeug.local.LocalProxy] 这个类:
> from werkzeug.local import LocalProxydb = LocalProxy(get_db)
这样的话用户就可以直接通过访问 db 来获取数据句柄了, db 已经在内部完成了对 get_db() 的调用。
© 版权所有 2013, Armin Ronacher.
- 欢迎使用 Flask
- 前言
- 给有经验程序员的前言
- 安装
- 快速入门
- 教程
- 介绍 Flaskr
- 步骤 0: 创建文件夹
- 步骤 1: 数据库模式
- 步骤 2: 应用设置代码
- 步骤 3: 创建数据库
- 步骤 4: 请求数据库连接
- 步骤 5: 视图函数
- 步骤 6: 模板
- 步骤 7: 添加样式
- 福利: 应用测试
- 模板
- 测试 Flask 应用
- 记录应用错误
- 配置处理
- 信号
- 即插视图
- 应用上下文
- 请求上下文
- 用蓝图实现模块化的应用
- Flask 扩展
- 与 Shell 共舞
- Flask 代码模式
- 大型应用
- 应用程序的工厂函数
- 应用调度
- 使用 URL 处理器
- 部署和分发
- 使用 Fabric 部署
- 在 Flask 中使用 SQLite 3
- 在 Flask 中使用 SQLAlchemy
- 上传文件
- 缓存
- 视图装饰器
- 使用 WTForms 进行表单验证
- 模板继承
- 消息闪现
- 用 jQuery 实现 Ajax
- 自定义错误页面
- 延迟加载视图
- 在 Flask 中使用 MongoKit
- 添加 Favicon
- 数据流
- 延迟请求回调
- 添加 HTTP Method Overrides
- 请求内容校验码
- 基于 Celery 的后台任务
- 部署选择
- mod_wsgi (Apache)
- 独立 WSGI 容器
- uWSGI
- FastCGI
- CGI
- 聚沙成塔
- API
- JSON 支持
- Flask 中的设计决策
- HTML/XHTML 常见问题
- 安全注意事项
- Flask 中的 Unicode
- Flask 扩展开发
- Pocoo 风格指引
- Python 3 支持
- 升级到最新版本
- Flask Changelog
- 许可证
- 术语表