使用 URL 處理器

變更日誌

在版本 0.7 中新增。

Flask 0.7 引入了 URL 處理器的概念。這個想法是,您可能有一堆資源,它們的 URL 中有共同的部分,但您不總是想明確地提供這些部分。例如,您可能有一堆 URL 包含語言代碼,但您不想在每個函數中都處理它。

當與藍圖結合使用時,URL 處理器特別有用。我們將在這裡處理應用程式特定的 URL 處理器以及藍圖的細節。

國際化的應用程式 URL

考慮像這樣的應用程式

from flask import Flask, g

app = Flask(__name__)

@app.route('/<lang_code>/')
def index(lang_code):
    g.lang_code = lang_code
    ...

@app.route('/<lang_code>/about')
def about(lang_code):
    g.lang_code = lang_code
    ...

這是一個非常多的重複,因為您必須在每個函數中自行處理 g 物件上的語言代碼設定。當然,可以使用裝飾器來簡化此操作,但是如果您想從一個函數生成 URL 到另一個函數,您仍然需要顯式提供語言代碼,這可能會很煩人。

對於後者,這就是 url_defaults() 函數的用武之地。它們可以自動將值注入到 url_for() 的呼叫中。下面的程式碼檢查語言代碼是否尚未在 URL 值的字典中,以及端點是否需要名為 'lang_code' 的值

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

URL 映射的方法 is_endpoint_expecting() 可以用來判斷為給定的端點提供語言代碼是否有意義。

該函數的反向是 url_value_preprocessor()。它們在請求匹配後立即執行,並且可以根據 URL 值執行程式碼。這個想法是它們從值字典中提取資訊並將其放在其他地方

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

這樣您就不再需要在每個函數中將 lang_code 賦值給 g。您可以通過編寫自己的裝飾器來改進這一點,該裝飾器以語言代碼作為 URL 的前綴,但更優雅的解決方案是使用藍圖。一旦 'lang_code' 從值字典中彈出,它將不再轉發到視圖函數,從而將程式碼簡化為這樣

from flask import Flask, g

app = Flask(__name__)

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

@app.route('/<lang_code>/')
def index():
    ...

@app.route('/<lang_code>/about')
def about():
    ...

國際化的藍圖 URL

因為藍圖可以自動為所有 URL 添加一個通用字串作為前綴,所以很容易自動為每個函數執行此操作。此外,藍圖可以具有每個藍圖的 URL 處理器,這從 url_defaults() 函數中移除了很多邏輯,因為它不再需要檢查 URL 是否真的對 'lang_code' 參數感興趣

from flask import Blueprint, g

bp = Blueprint('frontend', __name__, url_prefix='/<lang_code>')

@bp.url_defaults
def add_language_code(endpoint, values):
    values.setdefault('lang_code', g.lang_code)

@bp.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code')

@bp.route('/')
def index():
    ...

@bp.route('/about')
def about():
    ...