URL Routing and Article Detail Pages
In this chapter, you will learn Django's dynamic routing configuration to implement article detail pages and link navigation between pages.
What is Dynamic Routing?
The homepage displays all articles, and each article needs its own independent detail page.
The URL should look like this:/post/1/、/post/2/, where the numeric part is the article's primary key (pk).
Dynamic routingAllows URLs to contain variables, and Django will automatically extract and pass them to the view function.
Configure dynamic routing
Example
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
# int:pk — integer parameter in the URL, named pk (primary key)
# name='post_detail' — name the route, referenced in templates with {% url %}
path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
Route Converter Explanation:
| Converter | Example path | Matching rules |
|---|---|---|
<int:pk> | /post/3/ | Match positive integer |
<str:slug> | /post/django-guide/ | Matches a string (excluding /) |
<slug:slug> | /post/django-guide/ | Matches letters, numbers, -, _ |
<uuid:id> | /post/uuid/ | Matches UUID format |
Write the detail page view
The detail page needs to query the corresponding article from the database based on the pk in the URL.
Example
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_detail(request, pk):
"""Article detail page"""
# get_object_or_404: query a single record
# Return the object if found; otherwise automatically return the 404 page (without writing try/except)
post = get_object_or_404(Post, pk=pk)
context = {
'post': post,
'title': f{post.title} - EXAMPLE Blog
}
return render(request, 'blog/post_detail.html', context)
get_object_or_404is Django's best practice. It is equivalent toPost.objects.get(pk=pk)+try/except Post.DoesNotExist, but the code is more concise. When users access a non-existent article ID, they will see a friendly 404 page instead of an error.
Create the detail page template
Example
{% extends 'blog/base.html' %}
{% block title %}{{ post.title }} - EXAMPLE Blog{% 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>
<!-- The body uses the |safe filter to render HTML (HTML content entered in Admin) -->
<div class="content">
{{ post.content|safe }}
</div>
<a href="{% url 'index' %}" class="back-link">← Back to Home</a>
</article>
{% endblock %}
Detail page style
Example
.post-view {
max-width: 720px;
margin: 0 auto;
}
.category-tag {
display: inline-block;
padding: 4px 12px;
background: #E8EEF5;
color: #3D71A6;
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;
}
|safeThe filter tells Django: this content is safe HTML, render it directly, don't escape it. When using safe, make sure the content is trustworthy (such as content you edited yourself in Admin). If it's user-submitted content, never add safe, otherwise there's an XSS risk.
Generating links in templates: {% url %}
Add detail page links to the article cards on the homepage.
Example
<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 %}It will automatically generate the correct URL based on the route name and parameters.
If the route changes later (e.g.,/post/Change to/article/), the links in the template will automatically update without manual modification.
Add get_absolute_url() to the model
Defining this method in the Post model allows the Admin backend, Django built-in tools, etc. to automatically find the detail page link.
Example
from django.urls import reverse
class Post(models.Model):
# ... field definitions ...
def __str__(self):
return self.title
def get_absolute_url(self):
# reverse: Look up URL based on route name and parameters
return reverse('post_detail', kwargs={'pk': self.pk})
Chapter summary
In this chapter, you have mastered the core of Django routing: dynamic routing.<int:pk>Passing parameters, get_object_or_404 safe query, {% url %} template tag to generate links, reverse URL lookup.
Now the blog has two pages: the homepage list and the article detail page. Clicking a card navigates to read the full article.
other extensions