Flask Web開發入門筆記(二) 1 Flask開啓調試模式 2 應用和請求上下文

1 Flask開啓調試模式

Flask 應用可以在調試模式中運行。在這個模式下,開發服務器默認會加載兩個便利的工具:重載器調試器
啓用重載器後, Flask 會監視項目中的所有源碼文件,發現變動時自動重啓服務器。在開發過程中運行啓動重載器的服務器特別方便,因爲每次修改並保存源碼文件後,服務器都會自動重啓,讓改動生效。
調試器是一個基於 Web 的工具,當應用拋出未處理的異常時,它會出現在瀏覽器中。此時, Web 瀏覽器變成一個交互式棧跟蹤,你可以在裏面審查源碼,在調用棧的任何位置計算表達式。

調試模式默認禁用。若想啓用,在執行 flask run 命令之前設定 FLASK_DEBUG=1 環境變量:

(venv) $ export FLASK_APP=hello.py
(venv) $ export FLASK_DEBUG=1
(venv) $ flask run
* Serving Flask app "hello"
* Forcing debug mode on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 273-181-528

注意:
當使用 app.run() 方法啓動服務器時,不會用到 FLASK_APP 和 FLASK_DEBUG 環境變量。若想以編程的方式啓動調試模式,就使用app.run(debug=True)

2 應用和請求上下文

Flask從客戶端收到請求時,要讓視圖函數能訪問一些對象,這樣才能處理請求。請求對象就是一個很好的例子,它封裝了客戶端發送的HTTP 請求。
要想讓視圖函數能夠訪問請求對象,一種直截了當的方式是將其作爲參數傳入視圖函數,不過這會導致應用中的每個視圖函數都多出一個參數。除了訪問請求對象,如果視圖函數在處理請求時還要訪問其他對象,情況會變得更糟。
爲了避免大量可有可無的參數把視圖函數弄得一團糟, Flask 使用上下文臨時把某些對象變爲全局可訪問。有了上下文,便可以像下面這樣編寫視圖函數:

from flask import request
@app.route('/')
def index():
    user_agent = request.headers.get('User-Agent')
    return '<p>Your browser is {}</p>'.format(user_agent)

注意,在這個視圖函數中我們把 request 當作全局變量使用。事實上, request 不可能是全局變量。試想,在多線程服務器中,多個線程同時處理不同客戶端發送的不同請求時,每個線程看到的 request 對象必然不同。 Flask 使用上下文讓特定的變量在一個線程中全局可訪問,與此同時卻不會干擾其他線程。

在 Flask 中有兩種上下文: 應用上下文和請求上下文。下表 列出了這兩種上下文提供的變量。

變量名 上下文 說明
current_app 應用上下文 當前應用的應用實例
g 應用上下文 處理請求時用作臨時存儲的對象,每次請求都會重設這個變量
request 請求上下文 請求對象,封裝了客戶端發出的 HTTP 請求中的內容
session 請求上下文 用戶會話,值爲一個字典,存儲請求之間需要“記住”的值

Flask 在分派請求之前激活(或推送)應用和請求上下文,請求處理完成後再將其刪除。應用上下文被推送後,就可以在當前線程中使用current_appg變量。類似地,請求上下文被推送後,就可以使用 request 和 session 變量。如果使用這些變量時沒有激活應用上下文或請求上下文,就會導致錯誤。

下述 Python shell 會話演示了應用上下文的使用方法:

>>> from hello import app
>>> from flask import current_app
>>> current_app.name
Traceback (most recent call last):
...
RuntimeError: working outside of application context
>>> app_ctx = app.app_context()
>>> app_ctx.push()
>>> current_app.name
'hello'
>>> app_ctx.pop()

在這個例子中,沒激活應用上下文之前就調用 current_app.name 會導致錯誤,但推送完上下文之後就可以調用了。注意,獲取應用上下文的方法是在應用實例上調用 app.app_context()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章