Vistas y plantillas — Renderizar lista de artículos

En este capítulo aprenderás a usar las vistas de Django para obtener datos de la base de datos y, junto con las plantillas, renderizar la lista de tarjetas de artículos de la página de inicio del blog.


El papel de las vistas (View)

La vista es la capa lógica central de Django, responsable de:

  • Recibir la solicitud del usuario (requestparámetro)
  • Consultar los datos necesarios de la base de datos
  • Pasar los datos a la plantilla para renderizar HTML y devolverlos al usuario

Hay dos formas de escribir vistas en Django:Vistas basadas en funciones (FBV)y vistas basadas en clases (CBV).

En los primeros ocho capítulos usamos preferentemente FBV: es más intuitiva y adecuada para que los principiantes comprendan el flujo de procesamiento de solicitudes.


Fundamentos de las vistas basadas en funciones

Una función de vista de Django reciberequestparámetro, y devuelveHttpResponseobjeto.

Ejemplo

# Ruta de archivo: blog/views.py
from django.shortcuts import render
from .models import Post

def index(request):
    """Página de inicio del blog: mostrar todos los artículos"""
    # Consultar todos los artículos de la base de datos (en orden cronológico inverso)
    posts = Post.objects.all().order_by('-created_at')

    # Los tres parámetros de render:
    # 1. request — objeto de solicitud
    # 2. Ruta de plantilla — blog/index.html
    # 3. diccionario context — datos pasados a la plantilla
    context = {
        'posts': posts,
        'title': 'EJEMPLO Blog - Inicio'
    }
    return render(request, 'blog/index.html', context)

render()es la función de acceso rápido más utilizada en Django, que combina: cargar plantilla → inyectar datos → generar HTML → devolver la respuesta.


Sintaxis de plantillas de Django

La sintaxis de plantillas de Django es muy similar a la sintaxis de plantillas de Vue3, pero hay algunas diferencias clave.

UsoPlantilla DjangoPlantilla Vue3
Salida de variable{{ variable }}{{ variable }}
Bucle{% for item in list %}...{% endfor %}v-for="item in list"
Condición{% if cond %}...{% endif %}v-if="cond"
Generación de URL{% url 'name' %}router-link to="name"
Herencia de diseño{% extends 'base.html' %}Anidamiento de componentes

Diferencia clave: las plantillas de Django usan{% %}para envolver etiquetas de control, Vue3 usav-directivas. Las plantillas de Django se renderizan en elservidor—el HTML se envía al navegador solo después de generarse; Vue3 en elnavegadorse renderiza—el navegador recibe el JS y luego ensambla el HTML.


Herencia de plantillas: base.html

Múltiples páginas comparten la misma barra de navegación y el mismo pie de página, usaherencia de plantillaspara evitar la repetición.

La plantilla padre define «bloques (block)» y la plantilla hija rellena el contenido específico.

Crear la plantilla padre base.html

Ejemplo

<!-- Ruta de archivo: blog/templates/blog/base.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Blog de EJEMPLO{% endblock %}</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background: #f5f5f5;
            color: #333;
        }
        .navbar {
            display: flex; justify-content: space-between; align-items: center;
            padding: 16px 40px; background: #fff;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        }
        .navbar .logo { font-size: 22px; font-weight: bold; color: #2c3e50; text-decoration: none; }
        .navbar a { margin-left: 20px; text-decoration: none; color: #333; }
        .container { max-width: 960px; margin: 40px auto; padding: 0 20px; }
        .footer { text-align: center; padding: 20px; color: #999; border-top: 1px solid #eee; }
        .section-title { font-size: 24px; margin-bottom: 20px; }
    </style>
    {% block extra_head %}{% endblock %}
</head>
<body>
    <!-- Barra de navegación -->
    <header class="navbar">
        <a href="/" class="logo">Blog de EJEMPLO</a>
        <nav>
            <a href="/">Inicio</a>
            <a href="#">Acerca de</a>
        </nav>
    </header>

    <!-- Área de contenido principal (rellenada por la subplantilla) -->
    <main class="container">
        {% block content %}
        {% endblock %}
    </main>

    <!-- Pie de página -->
    <footer class="footer">
        <p>© 2024 Blog de EJEMPLO. Powered by Django.</p>
    </footer>
</body>
</html>

Crear la plantilla hija index.html

Ejemplo

<!-- ruta del archivo: blog/templates/blog/index.html -->
<!-- extends debe estar al principio -->
{% extends 'blog/base.html' %}

{% block title %}{{ title }}{% endblock %}

{% block content %}
<h2 class="section-title">Artículos recientes</h2>

{% if posts %}
    <div class="article-grid">
        {% for post in posts %}
        <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>
        {% endfor %}
    </div>
{% else %}
    <p class="empty-tip">Aún no hay artículos, estad atentos.</p>
{% endif %}
{% endblock %}

Varios conceptos clave utilizados en la plantilla:

SintaxisSignificado
{% extends 'blog/base.html' %}Hereda la plantilla padre, debe escribirse en la primera línea
{% block content %}...{% endblock %}Rellena el bloque content definido en la plantilla padre
{{ post.category.name }}Acceder a los atributos del objeto relacionado mediante una clave externa
{{ post.summary|truncatechars:80 }}Filtro: recorta los primeros 80 caracteres
{{ post.created_at|date:"Y-m-d" }}Filtro: formatear fecha

En las plantillas de Django, losfiltrosse representan con el símbolo de tubería|después de la variable, para formatear la salida. Filtros comunes:date、truncatechars、length、default。


Añadir estilos a la lista de artículos

Agrega el siguiente CSS dentro de la etiqueta style de base.html:

Ejemplo

/* Diseño de cuadrícula de tarjetas de artículos */
.article-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 24px;
}

.article-card {
    background: #fff;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 2px 12px rgba(0,0,0,0.08);
    transition: transform 0.2s, box-shadow 0.2s;
}

.article-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

.card-content {
    padding: 20px;
}

.card-category {
    display: inline-block;
    padding: 2px 10px;
    background: #E8EEF5;
    color: #3D71A6;
    border-radius: 12px;
    font-size: 12px;
    margin-bottom: 8px;
}

.article-card h3 {
    font-size: 18px;
    margin-bottom: 8px;
    color: #222;
}

.article-card p {
    font-size: 14px;
    color: #666;
    line-height: 1.6;
    margin-bottom: 12px;
}

.card-date {
    font-size: 12px;
    color: #999;
}

.empty-tip {
    text-align: center;
    color: #999;
    padding: 60px 0;
    font-size: 16px;
}

Manos a la obra: verificar el efecto de la página de inicio

Confirma que se han hecho los siguientes puntos:

  • En models.py se han definido los modelos Post y Category, y se ha ejecutado migrate
  • En el panel de Admin se han ingresado al menos 3-5 artículos (asignados a diferentes categorías)
  • La función index en views.py consulta los artículos de la base de datos y los pasa a la plantilla
  • En urls.py, la ruta / apunta a la vista index

Inicia el servidor, accede a la página de inicio y deberías ver la lista de tarjetas de artículos renderizada dinámicamente a partir de los datos de la base de datos.


Resumen del capítulo

En este capítulo has dominado la cooperación central entre las vistas y las plantillas de Django: views.py consulta datos de la base de datos y los pasa al context, render() renderiza la plantilla, base.html como plantilla padre define el diseño + block, la plantilla hija hereda con extends y rellena el contenido, y la sintaxis de plantillas de Django ({{ }}, {% %}, filtros).

Ahora la página de inicio del blog está impulsada por la base de datos, ya no está codificada de forma fija.

Otras extensiones