# Django 模板中取得 URL:`request.path` vs `path_info` vs `get_full_path()` vs `build_absolute_uri()` 在 Django 模板中,經常需要取得目前的 URL。 * 導覽列「目前選單高亮」 * 登入後「回到原本瀏覽的頁面(next)」 * 建立 canonical URL / 共享連結 * 包含查詢字串的「目前頁面不變」連結 然而除了 `{{ request.path }}`,還有許多相似的屬性,容易混淆。今天我們將清楚比較以下四個: * `request.path` * `request.path_info` * `request.get_full_path()` * `request.build_absolute_uri()` --- ## `{{ request }}` 是從哪裡來的?{#sec-e3874691b2fc} {#sec-23391dbd09b4} 在模板中看到 `{{ request }}`,通常表示 **request context processor** 已啟用。 * `django.template.context_processors.request` 會將 `request` 放入模板上下文。 * 這個 context processor 會在 `TEMPLATES` 設定的 `OPTIONS['context_processors']` 中註冊。 簡言之,Django 預設已將 `request` 加入全域上下文,除非開發者特意移除,使用者可以無縫使用。 `request` 物件本身是 Django 在接收請求時建立的 `HttpRequest`(實際上是 WSGI/ASGI 請求子類),並傳遞給視圖。這個物件包含 `path`、`path_info` 等屬性。 ![Django 這位魔術師從帽子裡抽出工具的圖像](/media/editor_temp/6/c112847e-a9ca-4d58-9a3f-076a20bfbef7.png) --- ## 一句話結論:四個屬性如何記住?{#sec-0f722c9bd67c} {#sec-09d7c0f4ea94} * **`path`**:去除域名,只保留路徑 * **`path_info`**:應用程式實際看到的路徑(去除腳本前綴) * **`get_full_path()`**:`path` + 查詢字串 * **`build_absolute_uri()`**:完整 URL(包含協定、主機、路徑) 現在我們逐一詳細說明。 --- ## 1) `request.path`:無域名的「路徑」{#sec-26a629a2d24e} {#sec-1f43c988e837} `request.path` 只回傳請求路徑,沒有協定或域名。範例: * `/music/bands/the_beatles/` ### 何時有用?{#sec-b307f735685f} {#sec-cc691ffe023e} * 菜單高亮等簡單比較 ```django {% if request.path == "/settings/" %}active{% endif %} ``` * 「這頁屬於哪個分類?」的前綴比較 ```django {% if request.path|slice:":5" == "/api/" %}...{% endif %} ``` --- ## 2) `request.path_info`:部署環境中更穩定的「實際路徑」{#sec-fd1e8e14948f} {#sec-b326c8c70759} Django 文件的重點是: * 某些伺服器設定會將 URL 路徑分為 **腳本前綴(SCRIPT_NAME)** 與 **path info**。 * `path_info` 永遠包含 **path info 部分**(即不受環境影響)。 簡單來說,在應用程式被掛載於 `/app` 等子路徑(反向代理、子路徑部署)時,`path` 與 `path_info` 可能不同。 ### 何時有用?{#sec-2985f0c9cd7c} {#sec-20723533eb57} * 考慮子路徑部署(如 `/app/`)時,想以「應用程式基準路徑」判斷 * 測試/正式環境前綴可能不同 > 若只在單一域名根目錄 (`/`) 運行,`path` 與 `path_info` 通常相同;環境改變時差異才顯現。 --- ## 3) `request.get_full_path()`:`path` + 查詢字串{#sec-1364e4e65388} {#sec-491e763b4c8b} `get_full_path()` 回傳 **`path` 加上查詢字串** 的值。範例: * `/music/bands/the_beatles/?print=true` ### 何時有用?{#sec-0ac89fe1b7cd} {#sec-dc1f582f173b} * 需要「目前頁面不變」的分享/重新整理/返回連結 ```django 重新整理連結 ``` * 登入/權限檢查後回到原頁面時的 `next` ```django 登入 ``` > 參考:Django 也有 `get_full_path_info()`,基於 `path_info`。雖非本比較範圍,但了解差異有助於選擇。 --- ## 4) `request.build_absolute_uri()`:包含協定與域名的「完整 URL」{#sec-0ba80b4c4700} {#sec-3a82ca9fb9db} `build_absolute_uri()` 以目前請求為基礎,產生 **絕對 URI**。 範例: * `https://example.com/music/bands/the_beatles/?print=true` ### 何時有用?{#sec-428d3d6b9613} {#sec-21182945b56b} * 需要域名的電子郵件/訊息分享連結 * canonical URL、og:url 等 meta 標籤 * 對外系統回呼 URL ### 注意事項{#sec-b24dccc132d6} {#sec-7b206b5c7631} `build_absolute_uri()` 依賴請求的 Host 資訊(內部使用 `get_host()`)。 * 這並非實際請求 URL;若 Nginx 反向代理或 Django 中自訂 `get_host()`,產生的 URL 可能與瀏覽器實際 URL 不同。 * 若實作了域名相關邏輯,請同時檢查部署設定,避免產生意外的域名/協定。 --- ## 結論與摘要{#sec-bd7ea169a316} {#sec-324a7afdfaba} * **模板中菜單高亮** → `request.path` * **子路徑部署/代理環境下穩定比較** → `request.path_info` * **包含查詢字串的「目前頁面」** → `request.get_full_path()` * **對外完整連結(含域名)** → `request.build_absolute_uri()` --- **相關文章**: - [反向代理是什麼?與正向代理的差異、目的、使用情境一覽](/ko/whitedec/2025/12/10/reverse-proxy-forward-proxy-differences/) - [從零開始學 Django:從 HTTP 開始的學習路徑](/ko/whitedec/2025/12/22/django-first-learning-roadmap/)