Plantillas de Django
El sistema de plantillas de Django (Template System) es un componente central que se utiliza para separar la lógica de negocio (Python) de la capa de presentación (HTML), y permite a los desarrolladores generar páginas HTML dinámicamente mediante etiquetas y variables simples.
En el capítulo anterior utilizamosdjango.http.HttpResponse()para generar"Hello World!", esta forma mezcla los datos con las vistas y no se ajusta al pensamiento MVT de Django.
En este capítulo presentaremos en detalle la aplicación de las plantillas de Django. Una plantilla es un texto que se utiliza para separar la forma de presentación del documento de su contenido.
| Función | Sintaxis/Ejemplo | Caso de uso |
|---|---|---|
| Renderizado de variables | {{ variable }} | Mostrar datos dinámicamente |
| Control lógico | {% if %}, {% for %} | Renderizado condicional/bucles |
| Herencia de plantillas | {% extends %}, {% block %} | Evitar estructuras HTML repetidas |
| Archivos estáticos | {% static 'path' %} | Cargar CSS/JS/imágenes |
| Filtros personalizados | @register.filter | Ampliar las funciones de las plantillas |
Ejemplo de aplicación de plantillas
Continuando con el proyecto del capítulo anterior, crearemos el directorio templates dentro del directorio HelloWorld y el archivo ejemplo.html. La estructura completa del directorio es la siguiente:
HelloWorld/
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- settings.py
| |-- settings.pyc
| |-- urls.py
| |-- urls.pyc
| |-- views.py
| |-- views.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- manage.py
`-- templates
`-- ejemplo.html
El código del archivo ejemplo.html es el siguiente:
Código del archivo HelloWorld/templates/ejemplo.html:
De la plantilla sabemos que las variables utilizan dobles llaves{{ }}。
A continuación, debemos indicar a Django la ruta del archivo de plantilla. Abra el archivo HelloWorld/HelloWorld/settings.py y modifiqueTEMPLATESenDIRSPara[BASE_DIR / "templates"], como se muestra a continuación:
Código del archivo HelloWorld/HelloWorld/settings.py:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / "templates"], # Ubicación de la modificación
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
...
Ahora modificamos views.py y añadimos un nuevo objeto para enviar datos a la plantilla:
Código del archivo HelloWorld/HelloWorld/views.py:
Se puede ver que aquí usamos render en lugar del HttpResponse utilizado anteriormente. render también utiliza un diccionario context como parámetro.
Los pares clave-valor de los elementos del diccionario contexthellocorresponden a las variables de la plantilla.{{ hello }}。
Código del archivo HelloWorld/HelloWorld/urls.py:
A continuación, entramos en el directorio HelloWorld e ingresamos el siguiente comando para iniciar el servidor:
python3 manage.py runserver 0.0.0.0:8000
Visite nuevamentehttp://127.0.0.1:8000/ejemplo, podrá ver la página:

Así completamos el uso de plantillas para generar datos, logrando la separación entre datos y vistas.
A continuación, presentaremos en detalle las reglas de sintaxis comunes en las plantillas.
Etiquetas de plantillas de Django
Sintaxis:
{% tag %}
Controla la lógica de la plantilla. Etiquetas comunes:
| Etiqueta | Propósito |
|---|---|
{% for %} | Recorrer en bucle listas/diccionarios |
{% if %} | Evaluación de condiciones |
{% extends %} | Heredar la plantilla base |
{% block %} | Definir bloques de contenido que pueden ser sobrescritos por plantillas hijas |
{% include %} | Incrustar fragmentos de otras plantillas |
{% url %} | Resolución inversa de URL (evita rutas codificadas) |
{% csrf_token %} | Generar token CSRF (para formularios POST) |
Variables
Sintaxis de la plantilla:
view:{"HTML变量名" : "views变量名"} HTML:{{变量名}}
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_name = "Ejemplo"
return render(request,"ejemplo.html", {"name":views_name})
ejemplo.html en templates:
<p>{{ name }}</p>

Visite nuevamente http://127.0.0.1:8000/ejemplo, podrá ver la página:

Listas
En ejemplo.html dentro de templates, se puede usar.el índice para obtener el elemento correspondiente.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_list = ["Ejemplo1","Ejemplo2","Ejemplo3"]
return render(request, "ejemplo.html", {"views_list": views_list})
Código del archivo HelloWorld/templates/ejemplo.html:
Visita nuevamente http://127.0.0.1:8000/ejemplo y verás la página:

Diccionarios
En ejemplo.html en templates, se puede usar.clavepara obtener el valor correspondiente.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_dict = {"name":"Tutorial para novatos"}
return render(request, "ejemplo.html", {"views_dict": views_dict})
Código del archivo HelloWorld/templates/ejemplo.html:
Visita nuevamente http://127.0.0.1:8000/ejemplo y verás la página:

Filtros
Sintaxis de plantillas:{{ nombre de variable | filtro: parámetro opcional }}
Los filtros de plantilla pueden modificar la variable antes de que se muestre. Los filtros usan el carácter de tubería (pipe), como se muestra a continuación:
{{ name|lower }}
La variable {{ name }} se procesa con el filtro lower, que convierte el texto de mayúsculas a minúsculas.
Los filtros de tubería pueden ser *encadenados*, es decir, la salida de una tubería de filtro puede ser la entrada de la siguiente:
{{ my_list|first|upper }}
El ejemplo anterior toma el primer elemento y lo convierte a mayúsculas.
Algunos filtros tienen parámetros. Los parámetros del filtro siguen a los dos puntos y siempre se incluyen entre comillas dobles. Por ejemplo:
{{ bio|truncatewords:"30" }}
Esto mostrará las primeras 30 palabras de la variable bio.
Otros filtros:
- addslashes: añade una barra invertida antes de cualquier barra invertida, comilla simple o comilla doble.
- date: formatea un objeto date o datetime según el parámetro de cadena de formato especificado. Ejemplo:
{{ pub_date|date:"F j, Y" }} - length: devuelve la longitud de la variable.
default
default proporciona un valor predeterminado a la variable.
Si el valor booleano de la variable pasada por views es false, se usa el valor predeterminado especificado.
Los siguientes valores son false:
0 0.0 False 0j "" [] () set() {} None
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
name =0
return render(request, "ejemplo.html", {"name": name})
Código del archivo HelloWorld/templates/ejemplo.html:
Visita nuevamente http://127.0.0.1:8000/ejemplo y verás la página:

length
Devuelve la longitud del objeto, aplicable a cadenas y listas.
Para diccionarios devuelve el número de pares clave-valor; para conjuntos, devuelve la longitud después de eliminar duplicados.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
name ="Tutorial para novatos"
return render(request, "ejemplo.html", {"name": name})
Código del archivo HelloWorld/templates/ejemplo.html:
Visita nuevamente http://127.0.0.1:8000/ejemplo y verás la página:

filesizeformat
Muestra el tamaño del archivo de una manera más legible (por ejemplo, '13 KB', '4.1 MB', '102 bytes', etc.).
Para diccionarios devuelve el número de pares clave-valor; para conjuntos, devuelve la longitud después de eliminar duplicados.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
num=1024
return render(request, "ejemplo.html", {"num": num})
Código del archivo HelloWorld/templates/ejemplo.html:
Visita nuevamente http://127.0.0.1:8000/ejemplo y verás la página:

date
Formatea una variable de fecha según el formato dado.
FormatoY-m-d H:i:sDevuelveaño-mes-día hora:minuto:segundoel tiempo en el formato.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
import datetime
now =datetime.datetime.now()
return render(request, "ejemplo.html", {"time": now})
Código del archivo HelloWorld/templates/ejemplo.html:
Visita nuevamente http://127.0.0.1:8000/ejemplo y verás la página:

truncatechars
Si el número total de caracteres de una cadena es mayor que la cantidad especificada, la parte final se truncará.
La cadena truncada terminará con...al final.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_str = "Tutorial para novatos"
return render(request, "ejemplo.html", {"views_str": views_str})
Código del archivo HelloWorld/templates/ejemplo.html:
Accede nuevamente a http://127.0.0.1:8000/ejemplo y verás la página:

safe
Marca la cadena como segura, no requiere escape.
Solo se puede usar safe si se garantiza que los datos enviados desde views.py son absolutamente seguros.
Tiene el mismo efecto que mark_safe en el backend views.py.
Django automáticamente escapa la sintaxis de etiquetas pasada desde views.py a los archivos HTML, invalidando su significado. Añadir el filtro safe le indica a Django que esos datos son seguros y no deben escaparse, permitiendo que su significado sea efectivo.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_str = "<a href='/index.html'>haz clic para saltar</a>"
return render(request, "ejemplo.html", {"views_str": views_str})
Código del archivo HelloWorld/templates/ejemplo.html:
Accede nuevamente a http://127.0.0.1:8000/ejemplo y verás la página:

Etiquetas if/else
La sintaxis básica es la siguiente:
{% if condition %}
... display
{% endif %}
O:
{% if condition1 %}
... display 1
{% elif condition2 %}
... display 2
{% else %}
... display 3
{% endif %}
Determina si se muestra según la condición. if/else admite anidamiento.
La etiqueta {% if %} acepta las palabras clave and, or o not para evaluar múltiples variables, o para negar la variable (not), por ejemplo:
{% if athlete_list and coach_list %}
athletes 和 coaches 变量都是可用的。
{% endif %}
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_num = 88
return render(request, "ejemplo.html", {"num": views_num})
Código del archivo HelloWorld/templates/ejemplo.html:
Accede nuevamente a http://127.0.0.1:8000/ejemplo y verás la página:

Etiqueta for
{% for %} nos permite iterar sobre una secuencia.
De manera similar al caso de la sentencia for de Python, la sintaxis del bucle es for X in Y, donde Y es la secuencia a iterar y X es el nombre de la variable utilizada en cada bucle concreto.
En cada bucle, el sistema de plantillas renderiza{% for %}y{% endfor %}todo el contenido entre.
Por ejemplo, dada una lista de atletas con la variable athlete_list, podemos usar el siguiente código para mostrar la lista:
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_list = ["Tutorial para novatos",Tutorial para novatos 1,Tutorial para novatos 2,Tutorial para novatos 3,]
return render(request, "ejemplo.html", {"views_list": views_list})
Código del archivo HelloWorld/templates/ejemplo.html:
Accede nuevamente a http://127.0.0.1:8000/ejemplo y verás la página:

Añadir un reversed a la etiqueta hace que la lista se itere en orden inverso:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
Código del archivo HelloWorld/templates/ejemplo.html:
Accede nuevamente a http://127.0.0.1:8000/ejemplo y verás la página:

Iterar sobre un diccionario: se puede usar directamente el diccionario.itemsmétodo, usando el desempaquetado de variables para obtener las claves y los valores por separado.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_dict = {"name":"Tutorial para novatos","age":18}
return render(request, "ejemplo.html", {"views_dict": views_dict})
Código del archivo HelloWorld/templates/ejemplo.html:
Accede nuevamente a http://127.0.0.1:8000/ejemplo y verás la página:

- forloop.counter: obtiene el número de iteración en orden, comenzando desde 1
- forloop.counter0: obtiene el número de iteración en orden, comenzando desde 0
- forloop.revcounter: obtiene el número de iteración en orden inverso, con el último número 1
- forloop.revcounter0: obtiene el número de iteración en orden inverso, con el último número 0
- forloop.first (normalmente se usa con la etiqueta if): devuelve True para el primer dato y False para los demás.
- forloop.last (generalmente se usa con la etiqueta if): el último dato devuelve True, los demás devuelven False.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_list = ["a", "b", "c", "d", "e"]
return render(request, "ejemplo.html", {"listvar": views_list})
Código del archivo HelloWorld/templates/ejemplo.html:
Visite nuevamente http://127.0.0.1:8000/ejemplo y podrá ver la página:

{% empty %}
La cláusula opcional {% empty %}: se ejecuta cuando el bucle está vacío (es decir, cuando el valor booleano del parámetro después de in es False).
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
views_list = []
return render(request, "ejemplo.html", {"listvar": views_list})
Código del archivo HelloWorld/templates/ejemplo.html:
Visite nuevamente http://127.0.0.1:8000/ejemplo y podrá ver la página:

Las etiquetas {% for %} se pueden anidar:
{% for athlete in athlete_list %}
<h1>{{ athlete.name }}</h1>
<ul>
{% for sport in athlete.sports_played %}
<li>{{ sport }}</li>
{% endfor %}
</ul>
{% endfor %}
Etiqueta de comentario
Los comentarios de Django usan {# #}.
{# Esto es un comentario #}
Etiqueta include
La etiqueta {% include %} permite incluir el contenido de otras plantillas en una plantilla.
El siguiente ejemplo incluye la plantilla nav.html:
{% include "nav.html" %}
csrf_token
csrf_token se usa en formularios form; su función es la protección contra falsificación de solicitudes entre sitios.
Si no se usa{% csrf_token %}la etiqueta, al usar el formulario form, si se intenta redirigir la página se producirá un error 403 de permisos.
Si se usa{% csrf_token %}la etiqueta, al enviar datos con el formulario form, se realizará correctamente.
Análisis:
Primero, se envía una solicitud al servidor para obtener la página de inicio de sesión; en este momento, el middleware csrf genera automáticamente una etiqueta input oculta. El valor del atributo value en esa etiqueta es una cadena aleatoria. El usuario obtiene la página de inicio de sesión y también obtiene esta etiqueta input oculta.
Luego, cuando el usuario necesita usar el formulario form para enviar datos, esta etiqueta input se envía junto con ellos al middleware csrf. La razón es que al enviar datos con el formulario form se incluyen todas las etiquetas input. Cuando el middleware csrf recibe los datos, comprueba si esa cadena aleatoria es la misma que le envió al usuario la primera vez. Si lo es, el envío de datos es exitoso; si no, devuelve un error 403 de permisos.
Etiquetas y filtros personalizados
1. Cree en el directorio de la aplicacióntemplatetagsel directorio (al mismo nivel que el directorio templates; el nombre del directorio solo puede ser templatetags).
HelloWorld/ |-- HelloWorld | |-- __init__.py | |-- __init__.pyc | |-- settings.py ... |-- manage.py `-- templatetags `-- templates
2. Cree cualquier archivo py en el directorio templatetags, por ejemplo:my_tags.py。
3. El código del archivo my_tags.py es el siguiente:
from django import template register = template.Library() #register的名字是固定的,不可改变
Modifique la configuración de la opción TEMPLATES en el archivo settings.py y agregue la configuración libraries:
Archivo de configuración settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR, "/templates",],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
"libraries":{ # Agregar estas tres líneas de configuración
'my_tags':'templatetags.my_tags' # Agregar estas tres líneas de configuración
} # Agregar estas tres líneas de configuración
},
},
]
...
4. Utilice el decorador @register.filter para personalizar filtros.
Nota:El decorador admite como máximo 2 parámetros.
@register.filter
def my_filter(v1, v2):
return v1 * v2
5. Utilice el decorador @register.simple_tag para personalizar etiquetas.
@register.simple_tag
def my_tag1(v1, v2, v3):
return v1 * v2 * v3
6. Antes de usar etiquetas y filtros personalizados, debe importar este archivo py en la parte superior del body del archivo html.
{% load my_tags %}7. Use filtros personalizados en HTML.
{{ 11|my_filter:22 }}
8. Use etiquetas personalizadas en HTML.
{% my_tag1 11 22 33 %}
9. Etiquetas semánticas
Importe mark_safe en este archivo py.
from django.utils.safestring import mark_safe
Al definir la etiqueta, use el método mark_safe para hacerla semántica, equivale al método html() de jQuery.
El efecto es el mismo que el del filtro safe en los archivos HTML del frontend.
@register.simple_tag
def my_html(v1, v2):
temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2)
return mark_safe(temp_html)
Use esta etiqueta personalizada en HTML para crear etiquetas dinámicamente en la página.
{% my_html "zzz" "xxx" %}
Configurar archivos estáticos
1. Cree el directorio statics en el directorio raíz del proyecto.

2. Agregue la siguiente configuración al final del archivo settings:
STATIC_URL = '/static/' # 别名
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "statics"),
]
3. Cree los directorios css, js, images y plugins en el directorio statics para colocar archivos css, archivos js, imágenes y plugins respectivamente.
4. Coloque el framework bootstrap en el directorio de plugins plugins.
5. Introduzca bootstrap en la etiqueta head del archivo HTML.
Nota:En este momento, en la ruta de referencia se debe usar el alias static del archivo de configuración, no el directorio statics.
<link rel="stylesheet" href="../static/plugins/bootstrap-3.3.7/dist/css/bootstrap.css.html">
Para usar en la plantilla, es necesario agregar{% load static %}código; el siguiente ejemplo importa una imagen desde el directorio estático.
Código del archivo HelloWorld/HelloWorld/views.py:
def ejemplo(request):
name =Tutorial para novatos
return render(request, "ejemplo.html", {"name": name})
Código del archivo HelloWorld/templates/ejemplo.html:
Visite nuevamente http://127.0.0.1:8000/ejemplo y podrá ver la página:

Herencia de plantillas
Las plantillas pueden reutilizarse mediante la herencia para reducir contenido redundante.
Por lo general, el encabezado y el pie de página de una página web son iguales; podemos lograr la reutilización mediante la herencia de plantillas.
La plantilla padre se utiliza para colocar contenido reutilizable; la plantilla hija hereda el contenido de la plantilla padre y coloca su propio contenido.
Plantilla padre
Etiqueta block...endblock:Es el área reservada en la plantilla padre; esta área se deja para que la plantilla hija complete contenido diferente. Los nombres de las distintas áreas reservadas no pueden ser iguales.
{% block 名称 %}
预留给子模板的区域,可以设置设置默认内容
{% endblock 名称 %}
Plantilla hija
La plantilla hija usa la etiqueta extends para heredar de la plantilla padre:
{% extends "父模板路径"%}
Si la plantilla hija no establece el contenido del área reservada de la plantilla padre, se utiliza el contenido predeterminado definido en la plantilla padre; por supuesto, también se puede dejar vacío.
La plantilla hija establece el contenido del área reservada de la plantilla padre:
{ % block 名称 % }
内容
{% endblock 名称 %}
A continuación, primero creamos el archivo base.html en el directorio templates del proyecto anterior; el código es el siguiente:
Código del archivo HelloWorld/templates/base.html:
En el código anterior, la etiqueta block llamada mainbody es la parte que puede ser reemplazada por los herederos (plantillas hijas).
Todas las etiquetas {% block %} le indican al motor de plantillas que las plantillas hijas pueden sobrescribir estas partes.
ejemplo.html hereda de base.html y reemplaza bloques específicos. El código modificado de ejemplo.html es el siguiente:
Código del archivo HelloWorld/templates/ejemplo.html:
La primera línea de código indica que ejemplo.html hereda el archivo base.html. Puede verse que aquí las etiquetas block con el mismo nombre se utilizan para reemplazar los bloques correspondientes de base.html.
Vuelva a visitar la dirección http://127.0.0.1:8000/ejemplo; el resultado es el siguiente:
