### 導航
- [索引](# "總目錄")
- [下一頁](# "請求上下文") |
- [上一頁](# "即插視圖") |
- [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
- 許可證
- 術語表