Templates

Django necesita una forma conveniente de generar HTML dinámicamente, ya que es un framework web. La aproximación más común utiliza plantillas. Una plantilla contiene las partes estáticas del resultado deseado en HTML así como algún sintaxis especial que describe cómo se insertará el contenido dinámico. Para ver un ejemplo práctico de creación de páginas HTML con plantillas, consulte Tutorial 3.

Un proyecto Django puede estar configurado con uno o varios motores de plantillas (o incluso cero si no se utilizan plantillas). Django incluye backends integrados para su propio sistema de plantillas, llamado lenguaje de plantillas de Django (DTL), y para el popular Jinja2. Los backends para otros lenguajes de plantillas pueden estar disponibles desde terceros. También puedes escribir tu propio backend personalizado, consulte Backend de plantilla personalizado

Django define una API estándar para cargar y renderizar plantillas independientemente del backend. Cargar consiste en encontrar la plantilla para un identificador dado y preprocesarla, generalmente compilándola a una representación en memoria. Renderizar significa interpolar la plantilla con datos de contexto y devolver la cadena resultante.

El lenguaje de plantillas de Django es el propio sistema de plantillas de Django. Hasta Django 1.8 era la única opción integrada disponible. Es una buena biblioteca de plantillas aunque sea bastante opinativa y tenga algunas idiosincrasias. Si no tienes una razón apremiante para elegir otro backend, debes utilizar el DTL, especialmente si estás escribiendo una aplicación pluggable y planeas distribuir plantillas. Las aplicaciones contribuyentes de Django que incluyen plantillas, como django.contrib.admin, utilizan el DTL.

Por razones históricas tanto el soporte genérico para motores de plantillas como la implementación del lenguaje de plantillas de Django viven en el namespace django.template.

Advertencia

El sistema de plantillas no es seguro frente a autores de plantillas no confiables. Por ejemplo, un sitio web no debería permitir que sus usuarios proporcionen sus propias plantillas, ya que los autores de plantillas pueden hacer cosas como realizar ataques XSS y acceder a propiedades de variables de plantilla que pueden contener información sensible.

El lenguaje de plantillas de Django

Sintaxis

Sobre esta sección

Esta es una visión general de la sintaxis del lenguaje de plantillas Django. Para detalles, consulte la referencia de la sintaxis del lenguaje.

Una plantilla Django es un documento de texto o una cadena de Python marcada con el lenguaje de plantillas Django. Algunas construcciones son reconocidas e interpretadas por el motor de plantillas. Las principales son variables y etiquetas.

Una plantilla se renderiza con un contexto. La renderización reemplaza las variables con sus valores, que se buscan en el contexto, y ejecuta las etiquetas. Todo lo demás se muestra tal como está.

La sintaxis del lenguaje de plantillas Django involucra cuatro constructos.

Variables

Una variable imprime un valor del contexto, que es un objeto dict-like que mapea claves a valores.

Las variables están rodeadas por {{ y }} de la siguiente manera:

My first name is {{ first_name }}. My last name is {{ last_name }}.

Con el contexto {'first_name': 'John', 'last_name': 'Doe'}, esta plantilla se renderiza a:

My first name is John. My last name is Doe.

La búsqueda en un diccionario, la búsqueda de atributos y las búsquedas de índice de listas están implementadas con una notación de punto:

{{ my_dict.key }}
{{ my_object.attribute }}
{{ my_list.0 }}

Si una variable resuelve a una función callable, el sistema de plantillas llamará a esa función sin argumentos y utilizará su resultado en lugar de la función callable.

Etiquetas

Las etiquetas proporcionan lógica arbitraria en el proceso de renderizado.

Esta definición es intencionalmente vaga. Por ejemplo, una etiqueta puede producir contenido, servir como estructura de control, por ejemplo, un «sentencia if» o un «bucle for», capturar contenido de una base de datos, o incluso habilitar acceso a otras etiquetas de plantilla.

Las etiquetas están rodeadas por {% y %} como este:

{% csrf_token %}

La mayoría de las etiquetas aceptan argumentos:

{% cycle 'odd' 'even' %}

Algunas etiquetas requieren etiquetas de inicio y fin:

{% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}

También está disponible una referencia de etiquetas integradas así como instrucciones para escribir etiquetas personalizadas.

Filtros

Los filtros transforman los valores de las variables y los argumentos de las etiquetas.

Se ven así:

{{ django|title }}

Con un contexto de {'django': 'el framework web para perfeccionistas con plazos'}, esta plantilla se renderiza a:

The Web Framework For Perfectionists With Deadlines

Algunos filtros toman un argumento:

{{ my_date|date:"Y-m-d" }}

Una referencia a los filtros integrados <ref-templates-builtins-filters> está disponible, así como las instrucciones para escribir filtros personalizados <howto-writing-custom-template-filters>.

Comentarios

Comentarios parecen esto:

{# this won't be rendered #}

Un {% comment %} tag proporciona comentarios de varias líneas.

Componentes

Sobre esta sección

Esta es una visión general de la API del lenguaje de plantillas Django. Para detalles, consulte la referencia de la API .

Motor

django.template.Engine encapsula una instancia del sistema de plantillas de Django. La razón principal para instanciar directamente un Engine es utilizar el lenguaje de plantillas de Django fuera de un proyecto de Django.

django.template.backends.django.DjangoTemplates es una capa de adaptación delgado que ajusta django.template.Engine a la API de backend de plantillas de Django.

Plantilla

django.template.Template representa un plantilla compilada. Las plantillas se obtienen con Engine.get_template() o Engine.from_string().

De manera similar django.template.backends.django.Template es una capa delgada que adapta django.template.Template a la API de plantilla común.

Contexto

django.template.Context almacena algunos metadatos además de los datos de contexto. Se pasa a Template.render() para renderizar una plantilla.

django.template.RequestContext es una subclase de Context que almacena el HttpRequest actual y ejecuta procesadores de contexto de plantillas.

La API común no tiene un concepto equivalente. Los datos de contexto se pasan en forma de dict plano y el HttpRequest actual se pasa por separado si es necesario.

Cargadores

Los cargadores de plantillas son responsables de localizar las plantillas, cargarlas y devolver objetos Template.

Django proporciona varios cargadores de plantilla integrados y admite cargadores de plantilla personalizados.

Procesadores de contexto

Los textos traducidos son:

Su uso principal es agregar datos comunes compartidos por todos los templates al contexto sin repetir código en cada vista.

Django proporciona muchos procesadores de contexto integrados <context-processors>, y también puedes implementar tus propios procesadores de contexto adicionales.

Soporte para motores de plantillas

Configuración

Los motores de plantillas se configuran con la configuración TEMPLATES. Es una lista de configuraciones, una por cada motor. El valor predeterminado es vacío. El archivo settings.py generado por el comando startproject define un valor más útil:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [],
        "APP_DIRS": True,
        "OPTIONS": {
            # ... some options here ...
        },
    },
]

BACKEND es la ruta de Python puntoada a una clase del motor de plantillas que implementa la API de backend de Django para plantillas. Los backends integrados son django.template.backends.django.DjangoTemplates y django.template.backends.jinja2.Jinja2.

Dado que la mayoría de los motores cargan las plantillas desde archivos, la configuración de nivel superior para cada motor contiene dos configuraciones comunes:

  • DIRS define una lista de directorios donde el motor debe buscar archivos fuente de plantilla, en orden de búsqueda.

  • APP_DIRS indica si el motor debe buscar plantillas dentro de aplicaciones instaladas. Cada backend define un nombre convencional para la subcarpeta dentro de las aplicaciones donde sus plantillas deben estar almacenadas.

Mientras que es poco común, es posible configurar varias instancias del mismo backend con diferentes opciones. En ese caso debes definir un nombre único NAME para cada motor.

OPTIONS contiene ajustes específicos de backend.

Uso

El módulo django.template.loader define dos funciones para cargar plantillas.

get_template(template_name, using=None)[fuente]

Esta función carga la plantilla con el nombre dado y devuelve un objeto Template.

El tipo exacto del valor de retorno depende del backend que cargó la plantilla. Cada backend tiene su propia clase Template.

get_template() intenta cada motor de plantillas en orden hasta que uno tenga éxito. Si la plantilla no se encuentra, levanta TemplateDoesNotExist. Si la plantilla se encuentra pero contiene sintaxis inválida, levanta TemplateSyntaxError.

Cómo las plantillas son buscadas y cargadas depende del backend y configuración de cada motor.

Si deseas restringir la búsqueda a un motor de plantillas particular, pasa el nombre del motor en el argumento using.

select_template(template_name_list, using=None)[fuente]

select_template() es igual que get_template(), excepto que toma una lista de nombres de plantilla. Intenta cada nombre en orden y devuelve la primera plantilla que exista.

Si falla la carga de una plantilla, pueden levantarse las siguientes dos excepciones definidas en django.template:

exception TemplateDoesNotExist(msg, tried=None, backend=None, chain=None)[fuente]

Esta excepción se levanta cuando no se puede encontrar un plantilla. Acepta los siguientes argumentos opcionales para poblar la plantilla post mortem en la página de depuración:

backend

La instancia del back-end de plantillas desde la que se originó la excepción.

tried

Una lista de fuentes que se intentaron al buscar la plantilla. Esto está formateado como una lista de tuplas conteniendo (origen, estado), donde origen es un objeto similar a origen y estado es una cadena con el motivo por el que no se encontró la plantilla.

chain

Una lista de excepciones intermedias TemplateDoesNotExist levantadas al intentar cargar la plantilla. Esto se utiliza por funciones, como get_template(), que tratan de cargar una plantilla dada desde múltiples motores.

exception TemplateSyntaxError(msg)[fuente]

Esta excepción se levanta cuando se encuentra una plantilla pero contiene errores.

Las objetos Template devueltos por get_template() y select_template() deben proporcionar un método render() con la siguiente firma:

Template.render(context=None, request=None)

Renta esta plantilla con un contexto dado.

Si se proporciona context, debe ser un dict. Si no se proporciona, el motor renderizará el template con un contexto vacío.

Si se proporciona request, debe ser un HttpRequest. Luego, el motor debería hacerlo y el token CSRF disponibles en el template. Cómo se logra esto es a elección de cada backend.

Aquí tienes un ejemplo del algoritmo de búsqueda. Para este ejemplo, la configuración de TEMPLATES es:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            "/home/html/example.com",
            "/home/html/default",
        ],
    },
    {
        "BACKEND": "django.template.backends.jinja2.Jinja2",
        "DIRS": [
            "/home/html/jinja2",
        ],
    },
]

Si llamas a get_template('story_detail.html'), aquí están los archivos que Django buscará, en orden:

  • /home/html/example.com/story_detail.html ('django' motor)

  • /home/html/default/story_detail.html ('django' motor)

  • /home/html/jinja2/story_detail.html ('jinja2' motor)

Si llamas a select_template(['story_253_detail.html', 'story_detail.html']), aquí está lo que buscará Django:

  • /home/html/example.com/story_253_detail.html ('django' motor)

  • /home/html/default/story_253_detail.html ('django' motor)

  • /home/html/jinja2/story_253_detail.html ('jinja2' motor)

  • /home/html/example.com/story_detail.html ('django' motor)

  • /home/html/default/story_detail.html ('django' motor)

  • /home/html/jinja2/story_detail.html ('jinja2' motor)

Cuando Django encuentra un template que existe, deja de buscar.

Utiliza django.template.loader.select_template() para una mayor flexibilidad

Puedes utilizar select_template() para cargar templates de forma flexible. Por ejemplo, si has escrito una noticia y quieres que algunas noticias tengan plantillas personalizadas, utiliza algo como select_template(['story_%s_detail.html' % story.id, 'story_detail.html']). De esta manera podrás utilizar una plantilla personalizada para una historia individual, con una plantilla de respaldo para las historias que no tienen plantillas personalizadas.

Es posible – y preferible – organizar templates en subdirectorios dentro de cada directorio que contenga templates. La convención es hacer un subdirectorio por cada aplicación Django, con subdirectorios dentro de esos subdirectorios según sea necesario.

Haz esto para tu propia tranquilidad. Almacenar todos los templates en el nivel raíz de un solo directorio se vuelve desordenado.

Para cargar un template que está dentro de un subdirectorio, utiliza una barra diagonal, como se muestra a continuación:

get_template("news/story_detail.html")

Utilizando la misma opción TEMPLATES anterior, esto intentará cargar los siguientes templates:

  • /home/html/example.com/news/story_detail.html ('django' motor)

  • /home/html/default/news/story_detail.html ('django' motor)

  • /home/html/jinja2/news/story_detail.html ('jinja2' engine)

Además, para reducir la naturaleza repetitiva de cargar y renderizar plantillas, Django proporciona una función de atajo que automatiza el proceso.

render_to_string(template_name, context=None, request=None, using=None)[fuente]

render_to_string() carga una plantilla como get_template() y llama a su método render() inmediatamente. Recibe los siguientes argumentos.

template_name

El nombre de la plantilla para cargar y renderizar. Si es una lista de nombres de plantillas, Django utiliza select_template() en lugar de get_template() para encontrar la plantilla.

context

Un dict que se utilizará como contexto de la plantilla para renderizar.

request

Una solicitud HTTP HttpRequest opcional que estará disponible durante el proceso de renderizado de la plantilla.

using

Un motor de plantillas NAME opcional. La búsqueda de la plantilla se restringirá a ese motor.

Ejemplo de uso:

from django.template.loader import render_to_string

rendered = render_to_string("my_template.html", {"foo": "bar"})

Consulte también la función de atajo render() que llama a render_to_string() y alimenta el resultado en un objeto HttpResponse adecuado para devolver desde una vista.

Finalmente, puedes utilizar directamente los motores configurados:

engines

Los motores de plantillas están disponibles en django.template.engines:

from django.template import engines

django_engine = engines["django"]
template = django_engine.from_string("Hello {{ name }}!")

La clave de búsqueda — 'django' en este ejemplo — es el nombre del motor: NAME.

Motores integrados

class DjangoTemplates[fuente]

Establece BACKEND a 'django.template.backends.django.DjangoTemplates' para configurar un motor de plantillas Django.

Cuando APP_DIRS es True, los motores DjangoTemplates buscan plantillas en la subdirectorio templates de las aplicaciones instaladas. Se mantuvo este nombre genérico por compatibilidad hacia atrás.

Los motores DjangoTemplates aceptan las siguientes opciones: OPTIONS:

  • 'autoescape': una booleana que controla si se habilita el escape de HTML.

    Por defecto, es True.

    Advertencia

    Establece solo a False si estás renderizando plantillas no de HTML!

  • 'context_processors': una lista de caminos de Python puntuados a llamables que se utilizan para poblar el contexto cuando se renderiza una plantilla con una solicitud. Estas llamables toman un objeto de solicitud como argumento y devuelven un dict de elementos a ser fusionados en el contexto.

    Los textos traducidos son:

    Véase RequestContext para obtener más información.

  • 'debug': una booleana que activa/desactiva el modo de depuración de plantillas. Si es True, la página de error con formato avanzado mostrará un informe detallado sobre cualquier excepción levantada durante la renderización de la plantilla. Este informe contiene el fragmento relevante de la plantilla con la línea correspondiente resaltada.

    Por defecto, se ajusta al valor del parámetro DEBUG.

  • 'loaders': una lista de caminos de Python a través de puntos para clases de cargadores de plantillas. Cada clase Loader sabe cómo importar plantillas desde una fuente particular. Opcionalmente, se puede utilizar un tupla en lugar de una cadena. El primer elemento de la tupla debería ser el nombre de la clase Loader, y los elementos posteriores se pasan a la clase Loader durante su inicialización.

    El valor por defecto depende de los valores de DIRS y APP_DIRS.

    Véase Tipos de cargadores para obtener más detalles.

  • 'string_if_invalid': la salida, como cadena, que el sistema de plantillas debe utilizar para variables inválidas (por ejemplo, con errores de ortografía).

    Por defecto, se ajusta a una cadena vacía.

    Véase Cómo se manejan las variables inválidas para obtener más detalles.

  • 'caracteres_de_archivo': el conjunto de caracteres utilizado para leer archivos de plantilla en disco.

    Por defecto es 'utf-8'.

  • 'bibliotecas': Un diccionario de etiquetas y rutas de Python puntuadas de módulos de etiquetas de plantilla para registrar con el motor de plantillas. Esto se puede utilizar para agregar nuevas bibliotecas o proporcionar etiquetas alternativas para las existentes. Por ejemplo:

    OPTIONS = {
        "libraries": {
            "myapp_tags": "path.to.myapp.tags",
            "admin.urls": "django.contrib.admin.templatetags.admin_urls",
        },
    }
    

    Las bibliotecas pueden cargarse pasando la clave correspondiente al tag {% load %}.

  • 'integrados': Una lista de rutas de Python puntuadas de módulos de etiquetas de plantilla para agregar a los integrados. Por ejemplo:

    OPTIONS = {
        "builtins": ["myapp.builtins"],
    }
    

    Las etiquetas y filtros de las bibliotecas integradas se pueden utilizar sin tener que llamar primero al tag {% load %}.

class Jinja2[fuente]

Requiere que Jinja2 esté instalado:

$ python -m pip install Jinja2

Establece BACKEND en 'django.template.backends.jinja2.Jinja2' para configurar un motor de Jinja2.

Cuando APP_DIRS es True, los motores Jinja2 buscan plantillas en la subcarpeta jinja2 de las aplicaciones instaladas.

La entrada más importante en OPTIONS es 'entorno'. Es una ruta de Python puntuada a un llamable que devuelve un entorno Jinja2. Por defecto es 'jinja2.Environment'. Django invoca ese llamable y pasa otras opciones como argumentos clave. Además, Django agrega valores por defecto que difieren de los de Jinja2 para algunas opciones:

  • 'autoescape': Verdadero

  • 'loader': un cargador configurado para DIRECTORIOS y DIRECTORIOS DE APLICACIÓN

  • 'auto_reload': settings.DEBUG

  • 'undefined': DebugUndefined si settings.DEBUG, de lo contrario Undefined

Los motores Jinja2 también aceptan las siguientes OPCIONES:

  • 'context_processors': una lista de caminos de Python puntuados a llamables que se utilizan para poblar el contexto cuando se renderiza una plantilla con una solicitud. Estas llamables toman un objeto de solicitud como argumento y devuelven un dict de elementos a ser fusionados en el contexto.

    Los textos traducidos son:

    Se desaconseja el uso de procesadores de contexto con plantillas Jinja2.

    Los procesadores de contexto son útiles con plantillas Django porque las plantillas Django no admiten la llamada a funciones con argumentos. Dado que Jinja2 no tiene esa limitación, se recomienda poner la función que utilizarías como un procesador de contexto en las variables globales disponibles para la plantilla utilizando jinja2.Environment tal como se describe a continuación. Puedes llamar a esa función en la plantilla:

    {{ function(request) }}
    

    Algunos procesadores de contexto de plantillas Django devuelven un valor fijo. Para las plantillas Jinja2, esta capa de indirección no es necesaria ya que puedes agregar constantes directamente en jinja2.Environment.

    El uso original para agregar procesadores de contexto para Jinja2 involucraba:

    • Realizar una computación costosa que depende de la solicitud.

    • Los resultados de la traducción son los siguientes:

    • Usar el resultado varias veces en cada plantilla.

    A menos que se cumplan todas estas condiciones, pasar una función a la plantilla es más acorde con el diseño de Jinja2.

La configuración por defecto está intencionalmente mantenida al mínimo. Si una plantilla se renderiza con una solicitud (por ejemplo, cuando se utiliza render()), el backend Jinja2 agrega los globales request, csrf_input y csrf_token al contexto. Aparte de eso, este backend no crea un entorno con sabor a Django. No conoce sobre filtros ni etiquetas de Django. Para utilizar APIs específicas de Django, debes configurarlas en el entorno.

Por ejemplo, puedes crear myproject/jinja2.py con este contenido:

from django.templatetags.static import static
from django.urls import reverse

from jinja2 import Environment


def environment(**options):
    env = Environment(**options)
    env.globals.update(
        {
            "static": static,
            "url": reverse,
        }
    )
    return env

y establecer la opción 'environment' a 'myproject.jinja2.environment'.

Luego podrías utilizar los siguientes constructos en plantillas de Jinja2:

<img src="{{ static('path/to/company-logo.png') }}" alt="Company Logo">

<a href="{{ url('admin:index') }}">Administration</a>

Los conceptos de etiquetas y filtros existen tanto en el lenguaje de plantillas de Django como en Jinja2, pero se utilizan de manera diferente. Dado que Jinja2 admite pasar argumentos a llamables en las plantillas, muchas características que requieren una etiqueta o filtro de plantilla en Django pueden lograrse llamando a una función en las plantillas de Jinja2, como se muestra en el ejemplo anterior. El espacio de nombres global de Jinja2 elimina la necesidad de procesadores de contexto de plantilla. El lenguaje de plantillas de Django no tiene un equivalente de los tests de Jinja2.