Enrutamiento de URL y página de detalle del artículo
En este capítulo aprenderás a configurar el enrutamiento dinámico de Django, para implementar la página de detalle del artículo y los enlaces de navegación entre páginas.
¿Qué es el enrutamiento dinámico?
La página de inicio muestra todos los artículos; cada artículo necesita su propia página de detalle independiente.
La URL debería verse así:/post/1/、/post/2/, donde la parte numérica es la clave primaria (pk) del artículo.
Enrutamiento dinámicoPermite que la URL contenga variables; Django las extrae automáticamente y las pasa a la función de vista.
Configurar el enrutamiento dinámico
Ejemplo
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
# int:pk — Parámetro entero en la URL, llamado pk (clave primaria)
# name='post_detail' — Da nombre a la ruta; se usa {% url %} en las plantillas para referenciarla
path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
Explicación de los convertidores de ruta:
| Convertidor | Ruta de ejemplo | Regla de coincidencia |
|---|---|---|
<int:pk> | /post/3/ | Coincide con enteros positivos |
<str:slug> | /post/django-guide/ | Coincide con una cadena (sin /) |
<slug:slug> | /post/django-guide/ | Coincide con letras, números, - y _ |
<uuid:id> | /post/uuid/ | Coincide con el formato UUID |
Escribir la vista de la página de detalle
La página de detalle debe consultar el artículo correspondiente en la base de datos según el pk de la URL.
Ejemplo
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_detail(request, pk):
"""Página de detalle del artículo"""
# get_object_or_404: consulta un único registro
# Si se encuentra, devuelve el objeto; si no, devuelve automáticamente la página 404 (sin escribir try/except)
post = get_object_or_404(Post, pk=pk)
context = {
'post': post,
'title': f'{post.title} - Blog de EJEMPLO'
}
return render(request, 'blog/post_detail.html', context)
get_object_or_404Es la mejor práctica de Django. Equivale aPost.objects.get(pk=pk)+try/except Post.DoesNotExist, pero el código es más limpio. Cuando el usuario accede a un ID de artículo que no existe, verá una página 404 amigable en lugar de un error.
Crear la plantilla de la página de detalle
Ejemplo
{% extends 'blog/base.html' %}
{% block title %}{{ post.title }} - Blog de EJEMPLO{% 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>
<!-- El cuerpo usa el filtro |safe para renderizar HTML (contenido HTML introducido en Admin) -->
<div class="content">
{{ post.content|safe }}
</div>
<a href="{% url 'index' %}" class="back-link">← Volver al inicio</a>
</article>
{% endblock %}
Estilos de la página de detalle
Ejemplo
.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;
}
|safeEl filtro le dice a Django: este contenido es HTML seguro, se renderiza directamente, no lo escapes. Al usar safe, asegúrate de que el contenido sea confiable (como el que tú mismo editas en Admin). Si es contenido enviado por el usuario, nunca debes añadir safe, de lo contrario hay riesgo de XSS.
Generar enlaces en la plantilla: {% url %}
Añade un enlace a la página de detalle en la tarjeta del artículo de la página de inicio.
Ejemplo
<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 %}Genera automáticamente la URL correcta según el nombre de la ruta y los parámetros.
Si más adelante la ruta cambia (por ejemplo,/post/se cambia a/article/), el enlace en la plantilla se actualizará automáticamente, sin necesidad de modificarlo manualmente.
Añadir get_absolute_url() al modelo
Definir este método en el modelo Post permite que el backend de Admin, las herramientas integradas de Django, etc., encuentren automáticamente el enlace a la página de detalle.
Ejemplo
from django.urls import reverse
class Post(models.Model):
# ... definición de campos ...
def __str__(self):
return self.title
def get_absolute_url(self):
# reverse resuelve la URL según el nombre de la ruta y los parámetros
return reverse('post_detail', kwargs={'pk': self.pk})
Resumen del capítulo
En este capítulo has dominado el núcleo del enrutamiento de Django: el enrutamiento dinámico<int:pk>Pasar parámetros, consultar de forma segura con get_object_or_404, generar enlaces con la etiqueta de plantilla {% url %} y resolver URLs con reverse.
Ahora el blog tiene dos páginas: la lista de la portada y la página de detalle del artículo. Al hacer clic en la tarjeta, puedes saltar para leer el contenido completo.
Otras extensiones