Usando plantillas en Django

Estándar

En esta nueva entrada, daremos una nueva vuelta de tuerca a nuestro buscador de frases de los Simpson. En la última entrada, vimos cómo hacer una aplicación interactiva. Pero tuvimos que romper algunas reglas por el camino: mezclamos código Python y HTML, y desactivamos funcionalidades de seguridad de Django para que funcionara. En esta entrada vamos a redimirnos y usar las plantillas HTML.

Por supuesto, en nuestro flujo de trabajo normal, usaremos las plantillas desde el principio, y por tanto no necesitaremos desactivar los mecanismos de seguridad de Django. El uso de las plantillas es una parte integral del modelo MVC. Específicamente, los patrones componen la parte View de MVC, aunque en Django se llama view a lo que en MVC es Controller. Pero eso no es relevante para nosotros.

Comenzamos por reactivar el middleware de protección CSRF en SQProject/settings.py:

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

En la última entrada creamos una vista en SQApp/views.py llamada buscarCita que usaba una variable htmlcode que contenía el código HTML para mostrar la página de búsqueda cuando se accedía por primera vez a la URL de la aplicación. Definimos htmlcode fuera de buscarCita porque era muy largo y dificultaba la lectura; pero sí definimos el código HTML de otras respuestas en el cuerpo de la función. De una u otra forma, estábamos codificando HTML dentro de código Python, con los contratiempos que eso podía causar. Afortunadamente, el flujo de trabajo de Django soluciona esto mediante el uso de las plantillas. Una plantilla es un documento HTML (o XML, JSON ...) con variables marcadas para ser rellenadas (renderizadas) por las vistas escritas en Python. Una vez rellenadas, las plantillas son devueltas por la vista y enviadas al cliente como respuesta. Esto nos permite desarrollar por separado el formato de las respuestas y el código que procesa los datos. Además, esto simplifica las funcionalidades de seguridad de Django.

Crearemos una plantilla HTML por cada tipo de respuesta. Para ello, creamos un nuevo directorio: SQapp/templates/. En ese directorio, creamos tres ficheros HTML: uno para la página de búsqueda, otro para los resultados y el último para los mensajes de error.

El formulario de búsqueda contendrá el código de htmlcode al que se le añade una etiqueta que usará Django para las funciones de seguridad:

<!-- File: SQapp/templates/buscar.html -->
<html>
	<head>
		<title>Buscar citas de los Simpson</title>
	</head>
	<body>
		<form action='buscarCita' method='POST'>
			{% csrf_token %}
			<input type='text' name='palabras' /> <input type='submit' value='Buscar' />
		</form>
	</body>
</html>

La etiqueta {% csrf_token %} deberá ser incluida siempre que tengamos un formulario POST.

El código de la plantilla para los mensajes de error tiene una única variable mensaje que será rellenada por la vista. en el lenguaje de plantillas de Django, una variable se define por su nombre y se rodea de dos corchetes. El valor rellenado sustituye el texto desde el primer corchete de apertura hasta el segundo de cierre.

<!-- File: SQapp/templates/error.html -->
<html>
	<head>
		<title>Error</title>
	</head>
	<body>
		<p>Error: {{mensaje}}</p>
	</body>
</html>

El código para los resultados de búsqueda es un poco más complejo, ya que hay un número indeterminado de variables que deben rellenarse, dependiendo del número de resultados. Django nos permite usar etiquetas de plantilla, que dota de unas capacidades básicas de procesado a las plantillas. Queremos que nuestra plantilla procese un conjunto de resultados y automáticamente añada un elemento p de HTML con los campos de cada resultado organizados debidamente. Para ello, usaremos la etiqueta for y usaremos la sintaxis para acceder a cada campo:

<!-- File: SQapp/templates/resultados.html -->
<html>
	<head>
		<title>Resultados de búsqueda</title>
	</head>
	<body>
		{% for cita in resultados %}
		<p>"{{cita.contenido}}" {{cita.personaje}} (T{{cita.temporada}}C{{cita.capitulo}})</p>
		{% endfor %}
	</body>
</html>

Una vez definidas las plantillas, reescribimos la vista para poder usarlas:

def buscarCita(request):
	if request.method == 'GET':
		# Primera peticion del cliente
		return render(request, 'buscar.html')
	else:
		# Segunda peticion
		palabras = request.POST['palabras'].split()
		if len(palabras) >= 1:
			resultados = CitaSimpsons.objects.filter(content__icontains = palabras[0])
			for palabra_adicional in palabras[1:]: # Filtrar por palabras adicionales
				resultados = resultados.filter(content__icontains = palabra_adicional)
			if len(resultados) > 0:
				return render(request, 'resultados.html', {'resultados':resultados})
			else:
				return render(request, 'error.html', {'mensaje':'No hay resultados'})
		else:
			# Controlar el caso de que el cliente envíe una petición vacía
			return render(request, 'error.html', {'mensaje':'Por favor, introduce términos de búsqueda'})

Usamos una nueva función render, que previamente debemos importar (from django.shortcuts import render), y que toma como argumentos la petición del usuario, un nombre de fichero guardado en el directorio templates de la aplicacióny un diccionario que contenga las varaibles que vamos a usar sobre la plantilla. La primera llamada a render no contiene variables, por lo que no le pasamos el tercer argumento. La segunda llamada contiene los resultados de la búsqueda, maoeados sobre la variable resultados de la plantilla resultados.html. Podemos ver que el código queda mucho más limpio así. El uso de la plantilla de error es similar.

Como se puede ver, no hemos tenido que realizar ninguna operación especial para que funcione la protección CSRF, aparte de añadir la etiqueta en el formulario HTML. Hechos los cambios, podemos ejecutar el código y veremos que los resultados son los mismos que antes, sólo que con un código mucho mejor organizado y seguro. Podemos modificar los ficheros HTML para decorarlos como queramos, o cambiar la forma en la que se muestren los resultados. También podremos hacerlo al revés: primero diseñar la página y luego convertirla en una plantilla. Es decir, podemos introducir tareas de diseño web sin tocar una sóla línea de código Python. Y aún mejor, podemos cambiar el tipo de documento que se envía a los usuarios; por ejemplo, podemos enviarles un documento JSON. Más sobre eso en la próxima entrada.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *