现在位置: 首页 > Django 教程 > 正文

URL 路由与文章详情页

本章你将学会 Django 的动态路由配置,实现文章详情页和页面之间的链接跳转。


动态路由是什么?

首页展示的是所有文章,每篇文章需要有自己的独立详情页。

URL 应该像这样:/post/1//post/2/,其中数字部分是文章的主键(pk)。

动态路由 允许 URL 中包含变量,Django 会自动提取并传入视图函数。


配置动态路由

实例

# 文件路径:blog/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    # int:pk — URL 中的整数参数,名为 pk(primary key)
    # name='post_detail' — 给路由命名,模板中用 {% url %} 引用
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
]

路由转换器说明:

转换器示例路径匹配规则
<int:pk>/post/3/匹配正整数
<str:slug>/post/django-guide/匹配字符串(不含 /)
<slug:slug>/post/django-guide/匹配字母、数字、-、_
<uuid:id>/post/uuid/匹配 UUID 格式

编写详情页视图

详情页需要根据 URL 中的 pk 从数据库查询对应的文章。

实例

# 文件路径:blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post

def post_detail(request, pk):
    """文章详情页"""
    # get_object_or_404:查询单条记录
    # 找到就返回对象,找不到自动返回 404 页面(不写 try/except)
    post = get_object_or_404(Post, pk=pk)

    context = {
        'post': post,
        'title': f'{post.title} - RUNOOB 博客'
    }
    return render(request, 'blog/post_detail.html', context)

get_object_or_404 是 Django 的最佳实践。它等价于 Post.objects.get(pk=pk) + try/except Post.DoesNotExist,但代码更简洁。用户访问不存在的文章 ID 时会看到友好的 404 页面,而非报错。


创建详情页模板

实例

<!-- 文件路径:blog/templates/blog/post_detail.html -->
{% extends 'blog/base.html' %}

{% block title %}{{ post.title }} - RUNOOB 博客{% endblock %}

{% block content %}
<article class="post-view">
    <span class="category-tag">{{ post.category.name }}</span>
    <h1>{{ post.title }}</h1>
    <time>{{ post.created_at|date:"Y-m-d" }}</time>

    <!-- 正文使用 |safe 过滤器渲染 HTML(Admin 中输入的 HTML 内容) -->
    <div class="content">
        {{ post.content|safe }}
    </div>

    <a href="{% url 'index' %}" class="back-link">← 返回首页</a>
</article>
{% endblock %}

详情页样式

实例

/* 在 base.html 的 style 中追加 */
.post-view {
    max-width: 720px;
    margin: 0 auto;
}

.category-tag {
    display: inline-block;
    padding: 4px 12px;
    background: #e8f5e9;
    color: #2e7d32;
    border-radius: 12px;
    font-size: 13px;
    margin-bottom: 12px;
}

.post-view h1 {
    font-size: 32px;
    margin-bottom: 12px;
    line-height: 1.4;
}

.post-view time {
    display: block;
    color: #999;
    font-size: 14px;
    margin-bottom: 30px;
}

.content {
    line-height: 1.8;
    font-size: 16px;
    color: #333;
}

.content h2 {
    margin: 24px 0 12px;
    font-size: 22px;
}

.content p {
    margin-bottom: 12px;
}

.back-link {
    display: inline-block;
    margin-top: 40px;
    color: #2c3e50;
    text-decoration: none;
}

|safe 过滤器告诉 Django:这段内容是安全的 HTML,直接渲染,不要转义。使用 safe 时要确保内容是可信的(如你自己在 Admin 中编辑的内容)。如果是用户提交的内容,绝对不能加 safe,否则有 XSS 风险。


模板中生成链接:{% url %}

在首页的文章卡片上添加详情页链接。

实例

<!-- 修改 blog/templates/blog/index.html 中的文章卡片 -->
<div class="article-grid">
    {% for post in posts %}
    <a href="{% url 'post_detail' post.pk %}" class="card-link">
        <div class="article-card">
            <div class="card-content">
                <span class="card-category">{{ post.category.name }}</span>
                <h3>{{ post.title }}</h3>
                <p>{{ post.summary|truncatechars:80 }}</p>
                <span class="card-date">{{ post.created_at|date:"Y-m-d" }}</span>
            </div>
        </div>
    </a>
    {% endfor %}
</div>

{% url 'post_detail' post.pk %} 会根据路由名称和参数自动生成正确的 URL。

如果以后路由变了(如 /post/ 改成 /article/),模板中的链接会自动更新,不需要手动修改。


模型添加 get_absolute_url()

在 Post 模型中定义此方法,可以让 Admin 后台、Django 内置工具等自动找到详情页链接。

实例

# 文件路径:blog/models.py 的 Post 类中添加
from django.urls import reverse

class Post(models.Model):
    # ... 字段定义 ...
    def __str__(self):
        return self.title

    def get_absolute_url(self):
        # reverse 根据路由名称和参数反查 URL
        return reverse('post_detail', kwargs={'pk': self.pk})

本章小结

本章你掌握了 Django 路由的核心:动态路由 <int:pk> 传递参数、get_object_or_404 安全查询、{% url %} 模板标签生成链接、reverse 反查 URL。

现在博客有了首页列表和文章详情页两个页面,点击卡片可以跳转阅读全文。