# 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-a1fcebe00edc} 在模板中看到 `{{ request }}`,通常表示 **request context processor** 已啟用。 * `django.template.context_processors.request` 會把 `request` 物件放進模板上下文。 * 只要在 `TEMPLATES` 設定的 `OPTIONS['context_processors']` 中啟用,它就會生效。 一般情況下,Django 預設就包含這個 processor,所以多數專案不需要額外設定;除非你刻意把它移除。 `request` 物件本身是 Django 接到請求後建立的 `HttpRequest`(實際上是 WSGI/ASGI 的子類),並傳到 view。它包含 `path`、`path_info` 等屬性。 ![Django 這位魔術師從帽子裡抽出工具的圖像](/media/editor_temp/6/c112847e-a9ca-4d58-9a3f-076a20bfbef7.png) --- ## 一句話記住四個差異 {#sec-0f722c9bd67c} * **`path`**:去掉域名/協定,只剩路徑 * **`path_info`**:應用程式看到的實際路徑(不含 script prefix) * **`get_full_path()`**:`path` + 查詢字串 * **`build_absolute_uri()`**:完整 URL(協定 + 主機 + 路徑 + 查詢字串) --- ## 1) `request.path`:無域名的「路徑」 {#sec-26a629a2d24e} `request.path` 只回傳路徑,不含協定或域名,例如: * `/music/bands/the_beatles/` ### 何時有用? {#sec-b307f735685f} * 菜單高亮等簡單比較 ```django {% if request.path == "/settings/" %}active{% endif %} ``` * 用前綴判斷類別(例如 API 區) ```django {% if request.path|slice:":5" == "/api/" %}...{% endif %} ``` --- ## 2) `request.path_info`:部署環境中更穩定的「實際路徑」 {#sec-fd1e8e14948f} Django 文件的重點是: * 某些伺服器配置會把 URL 分成 **script prefix(`SCRIPT_NAME`)** 與 **path info**。 * `path_info` 永遠是 **path info** 那一段,因此比較不受環境影響。 如果你的應用程式掛在 `/app` 之類的前綴下(反向代理、子路徑部署),`path` 與 `path_info` 就可能不同。 ### 何時有用? {#sec-2985f0c9cd7c} * 子路徑部署(如 `/app/`)需要用「應用程式視角」的路徑判斷 * 測試/正式環境的前綴可能不同 > 若只在根目錄 (`/`) 運行,兩者往往相同,因此容易忽略差異。 --- ## 3) `request.get_full_path()`:`path` + 查詢字串 {#sec-1364e4e65388} `get_full_path()` 會回傳路徑加上查詢字串,例如: * `/music/bands/the_beatles/?print=true` ### 何時有用? {#sec-0ac89fe1b7cd} * 需要「當前頁面原樣」的分享/重新整理/返回連結 ```django 重新整理連結 ``` * 建立登入後返回用的 `next` ```django 登入 ``` > Django 也有 `get_full_path_info()`(以 `path_info` 為基礎),本文不展開,但可以留意。 --- ## 4) `request.build_absolute_uri()`:包含協定與域名的「完整 URL」 {#sec-0ba80b4c4700} `build_absolute_uri()` 會根據當前請求產生絕對 URL,例如: * `https://example.com/music/bands/the_beatles/?print=true` ### 何時有用? {#sec-428d3d6b9613} * 電子郵件/訊息分享(需要完整域名) * canonical URL、`og:url` 等 meta 標籤 * 提供外部系統 callback URL ### 注意事項 {#sec-b24dccc132d6} `build_absolute_uri()` 依賴請求中的 Host 資訊(內部使用 `get_host()`),因此**不一定等同於使用者瀏覽器實際看到的 URL**。在反向代理(例如 Nginx)或多租戶(tenant)等自訂主機邏輯下,產生結果可能不同。使用前請確認你的部署與 proxy 設定。 --- ## 總結 {#sec-bd7ea169a316} * **模板中菜單高亮** → `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/)