Django テンプレートで URL を取得する方法:request.path vs path_info vs get_full_path vs build_absolute_uri
Django テンプレートで現在の URL が必要になる場面は多々あります。
\n- \n
- ナビゲーションで「現在のメニューをアクティブ化」 \n
- ログイン後に「元のページへ戻る(next)」 \n
- canonical URL / 共有リンクを作成 \n
- クエリストリングを含めて「現在のページそのまま」をリンクにする \n
しかし {{ request.path }} 以外にも似たようなものがいくつかあるため、混乱しやすいです。 今日は混乱しやすい以下の 4 つを整理して比較します。
- \n
request.path\nrequest.path_info\nrequest.get_full_path()\nrequest.build_absolute_uri()\n
\n
{{ request }} はどこから来るのか
\nテンプレートで {{ request }} が見えるということは、通常 request context processor が有効になっていることを意味します。
- \n
django.template.context_processors.requestが テンプレートコンテキストにrequestを注入 します。 \n- このコンテキストプロセッサは
TEMPLATES設定のOPTIONS[\'context_processors\']に登録されているときに動作します。 \n
つまり、Django は settings.TEMPLATES に request をグローバルコンテキストとして入れるようにデフォルトで設定されているため、開発者が意図的にこの設定を削除しない限り、Django ユーザーは不便なく自然に使用できます。
そして request オブジェクト自体は、Django がリクエストを受け取るときに HttpRequest(実際には WSGI/ASGI リクエストサブクラス)を作成し、ビューまで渡すオブジェクトです。このオブジェクトには path、path_info などの属性が含まれます。

\n
一行結論:4 つを覚えると便利
\n- \n
path:ドメインを除いた「パスのみ」 \npath_info:アプリが見る「実際のパス(スクリプトプレフィックス除外)」 \nget_full_path():path+ クエリストリング \nbuild_absolute_uri():スキーム+ホスト+パスまで全て(完全な URL) \n
それではそれぞれを正確に見ていきましょう。
\n\n
1) request.path:ドメインなしの「パス」
\nrequest.path は ドメイン/スキームなし でリクエストパスだけを返します。例は以下のような形です。
- \n
/music/bands/the_beatles/\n
いつ役立つか
\n- \n
- メニューのアクティブ化など単純比較 \n
django\n {% if request.path == "/settings/" %}active{% endif %}\n* 「このページはどのカテゴリ?」といったプレフィックス比較
django\n {% if request.path|slice:":5" == "/api/" %}...{% endif %}
\n
2) request.path_info:デプロイ環境に左右されにくい「実際のパス」
\nDjango ドキュメントのポイントは次のとおりです。
\n- \n
- あるサーバ設定では URL パスが スクリプトプレフィックス(SCRIPT_NAME) と path info に分かれます。 \n
path_infoはその中で path info 部分を常に含む(つまり環境に依存しにくい) \n
簡単に言えば、アプリが /app などのプレフィックス下にマウントされる構成(リバースプロキシ、サブパスデプロイなど)では path と path_info が異なる場合があります。
いつ役立つか
\n- \n
- サブパスデプロイ(例:
/app/以下でサービス)などの環境を考慮し「アプリ基準のパス」で判断したいとき \n - テスト/本番サーバでプレフィックスが変わる場合 \n
\n\n通常は単一ドメインルート(
\n/)で動かすとpathとpath_infoが同じになるため差を感じにくいです。\nしかし環境が変わると差が意味を持ちます。
\n
3) request.get_full_path():path + クエリストリングまで
\nget_full_path() は path にクエリストリングを付けた値 を返します。例は以下のような形です。
- \n
/music/bands/the_beatles/?print=true\n
いつ役立つか
\n- \n
- 「現在のページそのままを共有/リフレッシュ/戻る」リンクが必要なとき \n
django\n <a href="{{ request.get_full_path }}">リフレッシュリンク</a>\n* ログイン/権限チェック後に元のページへ戻る next を作るとき
django\n <a href="/login/?next={{ request.get_full_path|urlencode }}">ログイン</a>
\n\nちなみに Django には
\nget_full_path()以外にget_full_path_info()もあります。\n後者はpath_infoベースで動作します。今日の比較対象はではありませんが、差を知っておくと便利です。
\n
4) request.build_absolute_uri():スキーム+ドメインまで含む「完全な URL」
\nbuild_absolute_uri() は現在のリクエストを基に 絶対 URL(absolute URI) を作成します。
ざっくりこんな形になります。
\n- \n
https://example.com/music/bands/the_beatles/?print=true\n
いつ役立つか
\n- \n
- メール/メッセンジャー共有リンクのように ドメインが必須 な場合 \n
- canonical URL、og:url などのメタタグ \n
- 外部システムにコールバック URL を渡す \n
注意すべき点
\nbuild_absolute_uri() はホストを作る際にリクエストの Host 情報に依存します(内部的に get_host() を使用)。\n実際にブラウザから来た URL ではありません。\n多くの普通の状況では get_host() の値と実際の URL ドメインが一致することもありますが、Nginx がリバースプロキシである場合や Django ミドルウェアで開発者が意図的に get_host() の値を別のテナントホストに設定するロジックを作った場合、{{ request.build_absolute_uri }} の値が常に実際のブラウザ URL と一致するとは限りません。
したがって、nginx でも Django アプリ内部でもドメイン関連のロジックを実装している場合は、予想と異なるドメイン/スキームで生成される可能性があるので、デプロイ設定も併せて確認することをおすすめします。
\n\n
結論とまとめ
\n- \n
- テンプレートでメニューをアクティブ化 →
request.path\n - サブパスデプロイ/プロキシ環境まで安定して比較 →
request.path_info\n - クエリストリングまで含めて「現在のページそのまま」 →
request.get_full_path()\n - 外部へ出る完全なリンク(ドメイン含む) →
request.build_absolute_uri()\n
\n
関連記事を見る:
\n', '/media/editor_temp/6/c112847e-a9ca-4d58-9a3f-076a20bfbef7.png')