| この記事の要点 |
|
なぜ直書きしないのか
<!-- 直書き。URL 設計を変えると全テンプレートを直すことになる -->
<a href="/blog/2026/09/07/">記事</a>
<!-- 名前で参照。urls.py を変えても自動で追従する -->
<a href="{% url 'blog:detail' pk=article.pk %}">記事</a>
直書きは、サブディレクトリ配下に配置したときにも壊れます。{% url %} なら FORCE_SCRIPT_NAME やプレフィックスの変更にも追従します。
urls.py に名前を付ける
# config/urls.py
from django.urls import include, path
urlpatterns = [
path("blog/", include("blog.urls")),
]
# blog/urls.py
from django.urls import path
from . import views
app_name = "blog" # 名前空間
urlpatterns = [
path("", views.index, name="index"),
path("<int:pk>/", views.detail, name="detail"),
path("<int:year>/<int:month>/", views.archive, name="archive"),
path("tag/<slug:slug>/", views.tag, name="tag"),
]
テンプレートから参照する
<a href="{% url 'blog:index' %}">一覧</a>
<!-- 位置引数 -->
<a href="{% url 'blog:detail' article.pk %}">{{ article.title }}</a>
<!-- キーワード引数(読みやすい) -->
<a href="{% url 'blog:archive' year=2026 month=9 %}">2026年9月</a>
<!-- 変数に入れて使い回す -->
{% url 'blog:detail' article.pk as detail_url %}
<a href="{{ detail_url }}">詳細</a>
<a href="{{ detail_url }}#comments">コメント</a>
ビュー名は必ずクォートで囲みます。囲まないと変数として解釈され、NoReverseMatch になります。
クエリ文字列とフラグメント
<!-- {% url %} の中に ?page=2 は書けない。外に付ける -->
<a href="{% url 'blog:index' %}?page=2&sort=new">次のページ</a>
<!-- ページャーで現在の条件を保ちたいとき -->
<a href="?page={{ page_obj.next_page_number }}">次へ</a>
<!-- アンカー -->
<a href="{% url 'blog:detail' article.pk %}#comment-{{ comment.id }}">該当コメント</a>
HTML の属性値では & をエスケープして & と書くのが正式です。ブラウザは & のままでも解釈しますが、バリデータでは警告になります。
リンクの種類ごとの書き方
| 用途 | 書き方 |
|---|---|
| サイト内のページ | {% url 'blog:detail' pk %} |
| CSS / JS / 画像 | {% static 'css/style.css' %} |
| アップロードされたファイル | {{ article.image.url }} |
| モデルの詳細ページ | {{ article.get_absolute_url }} |
| 外部サイト | URL を直書き + rel="noopener" |
| メール | mailto: + アドレス |
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<img src="{{ article.image.url }}" alt="{{ article.title }}">
<a href="https://example.com/" target="_blank" rel="noopener noreferrer">外部</a>
{% static %} を使うには、そのテンプレートの先頭で {% load static %} が必要です。読み込みの詳細は 静的ファイルの読み込み を参照してください。
モデル側に URL を持たせる
from django.db import models
from django.urls import reverse
class Article(models.Model):
title = models.CharField(max_length=200)
def get_absolute_url(self):
return reverse("blog:detail", kwargs={"pk": self.pk})
<a href="{{ article.get_absolute_url }}">{{ article.title }}</a>
定義しておくと、CreateView や UpdateView の保存後の遷移先としても自動的に使われ、管理画面にも「サイト上で表示」ボタンが出ます。テンプレートではかっこを書かない点に注意してください。
Python 側で URL を作る
from django.shortcuts import redirect
from django.urls import reverse
url = reverse("blog:detail", kwargs={"pk": 1}) # '/blog/1/'
return redirect("blog:detail", pk=1) # 名前をそのまま渡せる
# メールなどに載せる完全な URL
full = request.build_absolute_uri(url) # 'https://example.com/blog/1/'
NoReverseMatch の直し方
NoReverseMatch: Reverse for 'detail' not found.
'detail' is not a valid view function or pattern name.
| 原因 | 確認するところ |
|---|---|
name= を付けていない | urls.py の path() |
| 名前空間を書き忘れ | app_name があるなら 'blog:detail' と書く |
| 引数の数が合わない | <int:pk> があるのに引数なしで呼んでいないか |
| 型が合わない | <int:pk> に文字列やスラッグを渡していないか |
| ビュー名をクォートしていない | {% url blog:detail %} は不可 |
include() していない | ルートの urls.py に登録されているか |
# 登録されている URL 名を一覧する
python manage.py shell -c "from django.urls import get_resolver; print(sorted(get_resolver().reverse_dict.keys()))"
一覧から詳細へリンクする
<ul>
{% for article in articles %}
<li>
<a href="{% url 'blog:detail' article.pk %}">{{ article.title }}</a>
<span>{{ article.created_at|date:"Y年n月j日" }}</span>
</li>
{% empty %}
<li>記事がありません</li>
{% endfor %}
</ul>
{% empty %} はループする対象が空だったときに使われます。{% if articles %} で囲む必要がありません。
いま開いているページを強調する
<nav>
<a href="{% url 'blog:index' %}"
class="{% if request.resolver_match.url_name == 'index' %}active{% endif %}">
一覧
</a>
</nav>
request.resolver_match には、いま処理されているルートの情報(url_name / app_name / kwargs)が入っています。パス文字列を比較するより壊れにくい方法です。
request をテンプレートで使うには、settings.py の TEMPLATES の context_processors に django.template.context_processors.request が入っている必要があります(既定で入っています)。
ページ送りのリンク
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">前へ</a>
{% endif %}
<span>{{ page_obj.number }} / {{ page_obj.paginator.num_pages }}</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">次へ</a>
{% endif %}
?page=2 だけを書くと現在の他の検索条件が消えます。条件を保ちたい場合は、ビュー側で組み立てた文字列を渡すのが確実です。
def index(request):
params = request.GET.copy()
params.pop("page", None)
return render(request, "blog/index.html", {
"page_obj": page_obj,
"query_string": params.urlencode(), # 'q=Python&sort=new'
})
<a href="?page={{ page_obj.next_page_number }}&{{ query_string }}">次へ</a>
安全面の注意
- ユーザーが入力した URL をそのまま
hrefに出さない —javascript:で始まる値を入れられる。http/httpsだけを許可する target="_blank"にはrel="noopener noreferrer"を付ける- Django のテンプレートは既定でエスケープされる。
|safeや{% autoescape off %}を安易に使わない - ログイン後の遷移先を
?next=で受け取るときは、外部ドメインでないことを検証する(ビューでリダイレクト)
関連
- テンプレート(Template) — 親カテゴリ
- URLディスパッチャー(ルーティング処理)
- ルーティングの作成
- 静的ファイルの読み込み
- viewからtemplateへの遷移方法
- ビューでリダイレクト
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38