HOWTO · Flask

在 Flask 中使用 url_for 建立動態 URL

了解 Flask 的 url_for() 如何根據檢視端點建立 URL、填入動態路由值、支援重新導向,並在 Jinja 範本中產生連結。

本頁內容

在 Flask 中,url_for() 會根據端點(通常是檢視函式的名稱)建立 URL。將路由值作為關鍵字引數傳入,即可填入動態路徑。此函式會回傳 URL 字串;若要讓瀏覽器前往該 URL,請在檢視函式中回傳 redirect() 回應。

url_for() 如何建立 URL

Flask 會為每個檢視函式註冊一個端點。預設情況下,端點名稱就是檢視函式的名稱,因此 url_for("index") 會指向名為 index 的檢視函式。Flask 會查找該端點對應的路由並建立 URL,讓連結依據路由定義產生,無須在應用程式各處重複寫入路徑字串。

結果會是 / 或 /users/Harry 這類路徑。如果路由包含變數區段,請使用相符的關鍵字名稱傳入其值。未用於路由的其他值會加到查詢參數中。建立 URL 不會發出請求,也不會重新導向訪客。

從檢視函式建立 URL

以下的小型應用程式定義了首頁檢視、個人資料檢視、重新導向檢視,以及一個 Jinja 頁面。它的測試用戶端會請求 Jinja 頁面,並在不啟動伺服器的情況下檢查重新導向回應。執行前,請先在 Python 環境中安裝 Flask。在提供的執行環境中,測試用戶端呈現了連結,並收到狀態碼 302 的回應;其 Location 標頭值為 /users/Harry。

執行此範例:

from flask import Flask, redirect, render_template_string, url_for

app = Flask(__name__)


@app.get("/")
def index():
    return "Home"


@app.get("/users/<string:user_name>")
def profile(user_name):
    return f"Profile: {user_name}"


@app.get("/go")
def go():
    return redirect(url_for("profile", user_name="Harry"))


@app.get("/links")
def links():
    return render_template_string(
        '<a href="{{ url_for(\'profile\', user_name=\'Josh\') }}">Profile</a>'
    )


with app.test_client() as client:
    page = client.get("/links")
    print(page.get_data(as_text=True))
    response = client.get("/go", follow_redirects=False)
    print(response.status_code)
    print(response.headers["Location"])
<a href="/users/Josh">Profile</a>
302
/users/Harry

端點引數是 profile,也就是檢視函式的名稱。Flask 處理 /go 時,url_for() 會建立個人資料頁面的路徑,而 redirect() 會回傳導向該路徑的重新導向回應。測試用戶端會先印出呈現後的連結,再印出重新導向狀態碼及其 Location 標頭。範例中可見的連結標籤「Profile」保留英文。使用同一個應用程式時,url_for("index") 則會建立首頁路徑。

傳入動態路由值

路由 /users/<string:user_name> 宣告了一個名為 user_name 的變數;呼叫 url_for("profile", user_name="Harry") 時,會為這個變數傳入值。Flask 會將該值放入路徑中,並在需要時進行 URL 編碼。端點名稱和各路由變數名稱必須與檢視函式及關鍵字引數一致,否則 URL 建構時就無法找到相符的路由。

例如,對於 /articles/<int:article_id> 這類路由,可使用 url_for("article", article_id=42) 傳入整數。未被路由變數使用的值,例如 sort="recent",會成為查詢參數。路徑結構使用路由變數,查詢資料則使用額外的關鍵字引數。

使用產生的 URL 重新導向

在檢視函式中,回傳 redirect(url_for("profile", user_name="Harry"))。url_for() 提供目的地路徑,而 redirect() 會建立告知瀏覽器前往該處的 HTTP 回應。範例中的 /go 檢視函式便採用此寫法。若只回傳 url_for(...),回應本文會是 URL 字串,瀏覽器不會因此前往該頁面。

路由變更時,這項差異尤其實用:重新導向仍會指向端點目前註冊的路由,因此檢視函式不必寫死路徑。請依需求決定是否重新導向,因為重新導向是對目前請求的回應,瀏覽器之後會另外請求目的地。

在 Jinja 範本中產生連結

在 Jinja 範本中,可在錨點的 href 屬性內使用相同的端點和路由值:

<a href="{{ url_for('profile', user_name='Josh') }}">Profile</a>

在此,profile 對應檢視函式名稱,而 user_name 則填入必要的路由區段。可執行範例會在 /links 呈現這段範本字串,因此產生的連結會指向個人資料路由。呈現後的連結標籤「Profile」維持英文。若範本儲存在檔案中,請使用 Flask 的 render_template("index.html") 回傳,並將檔案放在應用程式的 templates 目錄中。請勿傳入目的端點未宣告的路由值,端點名稱也必須與應用程式中的拼法完全一致。