Saltar a contenido

Herencia de Plantillas en Django

1. Introducción a la Herencia de Plantillas

En Django, muchas páginas de un sitio web comparten elementos comunes como el menú de navegación, el pie de página o incluso la estructura básica de HTML. La herencia de plantillas permite definir una plantilla base que contiene estos elementos y luego extenderla en otras plantillas.

Ventajas de usar Herencia de Plantillas

  • Reutilización de código: Los elementos comunes se definen una sola vez en la plantilla base.
  • Mantenimiento más fácil: Si quieres cambiar el menú o el footer, solo se modifica la plantilla base.
  • Consistencia en el diseño: Todas las páginas que extienden la plantilla base tendrán un diseño uniforme.

2. Iniciar un proyecto con varias páginas

Podemos eliminar el contenido del proyecto que estabamos usando para explicar archivos estáticos y empezar de nuevo. Recuerda que el comando para crear un proyecto es:

django-admin startproject myproject .

E inmediatemante tenemos que migrar la base de datos:

python manage.py migrate

Prueba a poner en marcha el servidor:

python manage.py runserver

Y que todo funciona correctamente.

Para ayudarnos en la explicación, vamos a crear un proyecto donde tendremos tres páginas: index, about y contact. Cada página tendrá un menú de navegación, un área principal (main) y un pie de página (footer).

2.1 Crear las rutas

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('about/', views.about, name='about'),
    path('contact/', views.contact, name='contact'),
]

2.2 Crear las vistas

# views.py
from django.shortcuts import render

def index(request):
    return render(request, 'index.html')

def about(request):
    return render(request, 'about.html')

def contact(request):
    return render(request, 'contact.html')

Modificar settings.py para añadir las rutas de las plantillas y los archivos estáticos:

# settings.py

TEMPLATES = [
    {
        ...
        'DIRS': [BASE_DIR / 'templates'],
        ...
    },
]

STATICFILES_DIRS = [BASE_DIR / 'static']

STATIC_URL = '/static/'

2.3 Crear plantillas iniciales sin herencia

<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>
    <nav>
        <a href="#">Home</a> | 
        <a href="#">About</a> | 
        <a href="#">Contact</a>
    </nav>
    <main>
        <h1>Página de inicio</h1>
        <p>Contenido de la página index</p>
    </main>
    <footer>
        <p>Mi sitio web &copy; 2025</p>
    </footer>
</body>
</html>

Vista de home

Página inicial

  • Repetir la misma estructura en about.html y contact.html con textos diferentes.
  • Levantar el servidor y acceder a las tres URLs para comprobar que funcionan.

Nota

En este punto tenemos que darnos cuenta que para crear tres páginas (un sitio web puede tener decenas) hemos tenido que repetir mucho código. Si queremos cambiar el menú o el footer, tendríamos que modificar cada plantilla individualmente. Aquí es donde la herencia de plantillas nos será de gran ayuda. Tenemos que conseguir que nuestro código HTML, python, o cualquier otro lenguaje, sea lo más DRY posible (Don't Repeat Yourself). De esta manera el mantenimiento será mucho más sencillo.

Para ello en los puntos siguientes vamos a ver las técnicas que nos ofrece Django para conseguirlo.


3. Crear una plantilla base

Lo primero será crear una plantilla base (para nuestro ejemplo es suficiente, para sitios más complejos se pueden crear varias plantillas base). Esta plantilla contendrá el esqueleto HTML común a todas las páginas, incluyendo el menú de navegación y el pie de página. De esta manera no habrá que repetir este código en cada plantilla.

3.1 Definir la plantilla base

La plantilla base es una estructura con la parte común, pero de alguna manera necesitamos definir las partes que serán diferentes en cada página. Para ello usamos los bloques (block). Los bloques son secciones expuestas en la plantilla base que pueden ser sobrescritas en las plantillas hijas. En el siguiente ejemplo vamos a definir cuatro bloques.

Crearemos una carpeta layouts/ dentro de templates/ para organizar mejor las plantillas.

<!-- templates/layouts/base.html -->
 {% load static %}
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}Mi Sitio{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
    {% block extra_css %}{% endblock %}
</head>
<body>
    <header>
        <nav>
            <a href="#">Home</a> | 
            <a href="#">About</a> | 
            <a href="#">Contact</a>
        </nav>
    </header>

    <main>
        {% block content %}
        <!-- Contenido de cada página -->
        {% endblock %}
    </main>

    <footer>
        <p>Mi sitio web &copy; 2025</p>
    </footer>

    <script src="{% static 'js/script.js' %}"></script>
    {% block extra_js %}{% endblock %}
</body>
</html>
  • {% block title %}: Se usa para sobrescribir el título de cada página.
  • {% block content %}: Se usa para colocar el contenido principal de la página.
  • {% block extra_css %} y {% block extra_js %}: Bloques opcionales para añadir CSS o JS específico en cada página.

3.2 Extender la plantilla base

Ahora podemos modificar los templates index.html, about.html y contact.html para que extiendan de base.html y sobrescriban los bloques definidos. De esta manera dejarán de tener el código repetido.

<!-- templates/index.html -->
{% extends 'base.html' %}

{% block title %}Página de Inicio{% endblock %}

{% block content %}
<h1>Página de inicio</h1>
<p>Contenido de la página index</p>
{% endblock %}
  • Repetir la misma estructura en about.html y contact.html cambiando el título y el contenido. En este punto si probamos el servidor obtendremos errores, ya que hacemos referencia a archivos estáticos que aún no existen. Lo veremos en el siguiente punto.

4. Añadir CSS y JS a la plantilla base

Ahora, aunque no es el objetivo del curso, vamos a dar un poco de estilo a nuestra web para que se vea mejor. Para ello vamos a crear un archivo CSS y un archivo JS y los enlazaremos en la plantilla base. Así también nos servirá para repasar cómo funcionan los archivos estáticos en Django.

4.1 Crear carpeta static/ y archivos

static/
    css/style.css
    js/script.js

El fichero style.css:

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

nav {
    background-color: #333;
    color: white;
    text-align: center;
    padding: 1em 0;
}

nav a {
    color: white;
    text-decoration: none;
    margin: 0 1em;
}

footer {
    background-color: #333;
    color: white;
    text-align: center;
    padding: 1em 0;
    position: fixed;
    width: 100%;
    bottom: 0;
}

main {
    max-width: 800px;
    margin: 2em auto;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
}

El fichero script.js:

document.addEventListener('DOMContentLoaded', function() {
    console.log("JavaScript cargado correctamente.");
});
  • Levantar el servidor y comprobar que el CSS se aplica a todas las páginas.

Vista con CSS aplicado

Página con CSS aplicado


5. Enlaces entre páginas.

Ahora llega el momento de recordar como creámos las rutas en el fichero urls.py y como funcionan los enlaces entre páginas:

# urls.py
from django.urls import path
from . import views
urlpatterns = [
    path('', views.index, name='index'),
    path('about/', views.about, name='about'),
    path('contact/', views.contact, name='contact'),
]
Podemos ver que le hemos dado un nombre a cada ruta con el parámetro name. Esto nos servirá para crear los enlaces entre páginas de una manera más flexible.

Nombre de las rutas

El nombre de las URLs debe ser único en todo el proyecto Django. Si dos rutas tienen el mismo nombre, Django lanzará un error. Es importante utilizarlos en los enlaces para evitar problemas si las rutas cambian en el futuro.

En lugar de usar href="#", podemos usar el template tag {% url %}:

<nav>
    <a href="{% url 'index' %}">Home</a> |
    <a href="{% url 'about' %}">About</a> |
    <a href="{% url 'contact' %}">Contact</a>
</nav>
  • Esto asegura que si cambias las URLs en urls.py, los enlaces se actualizarán automáticamente.

Levantamos el servidor y comprobamos que los enlaces funcionan correctamente.


6. Uso de include para fragmentos de código

Los templates de django pueden volverse complejos y tener mucho código. Para ello Django ofrece la posibilidad de incluir fragmentos de código HTML en otros archivos usando la etiqueta {% include %}. Es otra manera de mantener el código limpio, separado y fácil de mantener.

templates/layouts/includes/nav.html:

<nav>
    <a href="{% url 'index' %}">Home</a> |
    <a href="{% url 'about' %}">About</a> |
    <a href="{% url 'contact' %}">Contact</a>
</nav>

templates/layouts/includes/footer.html:

<footer>
    <p>Mi sitio web &copy; 2025</p>
</footer>

Luego, modificamos base.html para usar {% include %}:

<header>
    {% include 'layouts/includes/nav.html' %}
</header>
<footer>
    {% include 'layouts/includes/footer.html' %}
</footer>
  • El diseño se mantiene igual pero el código es más limpio y fácil de mantener.

7. Resumen

  • La herencia de plantillas permite crear una plantilla base y extenderla en otras páginas.
  • Los bloques (block) definen secciones que pueden sobrescribirse en plantillas hijas.
  • Se pueden añadir archivos CSS y JS en la plantilla base para que se apliquen a todas las páginas.
  • Los enlaces se pueden manejar con {% url %} para mayor flexibilidad.
  • Los fragmentos repetidos de código, como menú o footer, pueden separarse usando {% include %} para mantener el código limpio.

8. Ejercicio práctico

Ejercicio

Objetivo: Crear una página web con un título y un párrafo. Mediante un archivo CSS, cambia el color de fondo de la página y el estilo del texto. Además, añade un archivo JavaScript que muestre un mensaje de alerta cuando se cargue la página.

Pasos:

  1. Crea una plantilla base base.html con bloques para el título y el contenido.
  2. Crea una plantilla home.html que extienda de base.html y sobrescriba los bloques.
  3. Crea un archivo CSS que cambie el color de fondo y el estilo del texto.
  4. Crea un archivo JavaScript que muestre una alerta al cargar la página.
  5. Asegúrate de que los archivos CSS y JS se cargan correctamente en la plantilla base.

Resultado esperado: Una página web con un diseño personalizado y una alerta al cargar.

Solución
# views.py
def bienvenida(request):
    return render(request, 'bienvenida.html')
<!-- templates/bienvenida.html -->
{% extends 'base.html' %}           
{% block title %}Bienvenida{% endblock %}
{% block content %}
<h1>Bienvenida a mi sitio web</h1>  
<p>Este es un ejemplo de una página con CSS y JS.</p>
{% endblock %}
<!-- templates/base.html -->
{% load static %}
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}Mi Sitio{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
    {% block extra_css %}{% endblock %}
</head>
<body>
    <main>
        {% block content %}
        <!-- Contenido de cada página -->
        {% endblock %}
    </main>         
    <script src="{% static 'js/script.js' %}"></script>
    {% block extra_js %}{% endblock %}
</body>
</html>
body {
    background-color: lightblue;
    font-family: Arial, sans-serif;
}           
h1 {
    text-align: center;
    color: #333;
}
p {
    font-size: 18px;
    color: #666;
    text-align: center;
}