# Django 模板中获取 URL:`request.path` 与 `path_info`、`get_full_path`、`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}
在模板中看到 `{{ request }}`,通常意味着已开启 **request context processor**。
* `django.template.context_processors.request` 负责将 `request` 放入模板上下文。
* 该 context processor 在 `TEMPLATES` 设置的 `OPTIONS['context_processors']` 中注册后生效。
换句话说,Django 默认在 `settings.TEMPLATES` 中将 `request` 设为全局上下文,除非开发者刻意移除,否则用户可以无障碍使用。
`request` 对象本身是 Django 在接收请求时创建的 `HttpRequest`(实际上是 WSGI/ASGI 请求子类),并将其传递给视图。该对象包含 `path`、`path_info` 等属性。

---
## 一句话总结:四个属性的记忆方式 {#sec-0f722c9bd67c}
* **`path`**:去掉域名/协议,只保留路径
* **`path_info`**:应用看到的真实路径(去掉脚本前缀)
* **`get_full_path()`**:`path` + 查询字符串
* **`build_absolute_uri()`**:完整的 URL(协议+域名+路径+查询字符串)
现在我们逐一深入。
---
## 1) `request.path`:无域名的“路径(path)” {#sec-26a629a2d24e}
`request.path` 只返回 **不含域名/协议** 的请求路径。例如:
* `/music/bands/the_beatles/`
### 何时有用 {#sec-b307f735685f}
* 简单比较,例如菜单激活
```django
{% if request.path == "/settings/" %}active{% endif %}
```
* 判断“此页面属于哪个分类”,如前缀比较
```django
{% if request.path|slice:":5" == "/api/" %}...{% endif %}
```
---
## 2) `request.path_info`:在部署环境中更稳的“真实路径” {#sec-fd1e8e14948f}
Django 文档的核心要点是:
* 某些服务器配置会将 URL 路径拆分为 **脚本前缀(SCRIPT_NAME)** 与 **path info**。
* `path_info` 始终包含 **path info 部分**(即不受环境影响)。
简而言之,在应用挂载在 `/app` 等前缀下(反向代理、子路径部署等)时,`path` 与 `path_info` 可能不同。
### 何时有用 {#sec-2985f0c9cd7c}
* 需要考虑子路径部署(如 `/app/`)时,想用“应用基准路径”判断
* 测试/生产服务器前缀可能不同
> 通常在单域名根路径(`/`)下运行时,`path` 与 `path_info` 相同,难以感知差异;但环境变化后差异才显现。
---
## 3) `request.get_full_path()`:`path` + 查询字符串 {#sec-1364e4e65388}
`get_full_path()` 返回 **`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(absolute URI)**。
大致形式:
* `https://example.com/music/bands/the_beatles/?print=true`
### 何时有用 {#sec-428d3d6b9613}
* 需要域名的链接,例如邮件/聊天分享
* canonical URL、og:url 等元标签
* 向外部系统回调 URL
### 注意事项 {#sec-b24dccc132d6}
`build_absolute_uri()` 在构造主机时依赖请求的 Host 信息(内部使用 `get_host()`)。
**这并不一定是实际请求的 URL**。在大多数普通场景下,`get_host()` 的值与实际域名相符,但如果 Nginx 反向代理或 Django 中间件故意使用不同的 tenant host,`{{ request.build_absolute_uri }}` 的值可能与浏览器实际 URL 不一致。
因此,无论是在 nginx 还是 Django 应用内部实现任何域名相关逻辑时,都应检查部署设置,避免产生意外域名/协议。
---
## 结论与总结 {#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/)