Motor de búsqueda de citas de los Simpsons con Django

Estándar

En la entrada anterior, creamos una aplicación básica en Django que devolvía citas aleatorias de los Simpson. La aplicación no era interactiva, es decir, no procesaba la petición del cliente. En esta entrada, modificaremos nuestra aplicación para que sea interactiva. Concretamente, crearemos un buscador simple que nos devolverá las citas que contengan ciertas palabras.

Para empezar, plantearemos la interfaz de nuestra aplicación en torno al protocolo de comunicación cliente-servidor. Para ello, vamos a revisar dos tipos de peticiones HTTP: las de tipo GET, que suelen usarse para solicitar documentos, y las de tipo POST, que suelen usarse para enviar información del cliente al servidor. En la entrada anterior, nuestra aplicación sólo reaccionaba a la recepción de peticiones GET. Ahora, añadiremos la capacidad de procesar las peticiones POST. Estas peticiones contendrán las palabras de búsqueda enviadas por el cliente. Las peticiones GET se pueden usar para esto también, mediante el uso de parámetros en el URL; pero dejaremos eso de lado por el momento.

Desde el punto de vista del cliente, la petición POST se genera en un elemento form de un documento HTML. Este documento deberá ser enviado por el servidor, respondiendo a una primera petición del cliente. El intercambio de peticiones y respuestas HTML es un poco más complicado en esta aplicación.

requestsES

En primer lugar, veamos cómo es el primer documento HTML, y dejaremos para más adelante cómo implementar el protocolo. El código mínimo es el siguiente:

<html>
	<head>
		<title>Buscar citas de los Simpsons</title>
	</head>
	<body>
		<form action='buscarCita' method='POST'>
			<input type='text' name='palabras' /> <input type='submit' value='Buscar' />
		</form>
	</body>
</html>

La vista que estamos diseñando, deberá devolver este documento cuando reciba una petición GET, y procesar y devolver los resultados de la búsqueda cuando reciba una petición POST. Estos resultados también se devolverán como un documento HTML. El proceso de búsqueda consistirá en un filtrado del contenido de las citas, de modo que contengan todos los términos de búsqueda. El código resultante será el siguiente:

def buscarCita(request):
	if request.method == 'GET':
		# Primera petición del cliente
		return HttpResponse(htmlcode)
	else:
		# Segunda petición (búsqueda)
		palabras = request.POST['palabras'].split()
		if len(palabras) >= 1:
			resultados = SimpsonQuote.objects.filter(content__icontains = palabras[0])
			for palabra_adicional in palabras[1:]: # Filter by any additional terms
				resultados = resultados.filter(content__icontains = palabra_adicional)
			if len(resultados) > 0:
				respuesta = '<html><head><title>Search results</title></head><body>'
				for cita in resultados:
					respuesta += '<p>"' + cita.contenido + '" ' + cita.personaje + ' (T' + str(cita.temporada) + 'C' + str(cita.capitulo) + ')</p>'
				respuesta += '</body></html>'
				return HttpResponse(respuesta)
			else:
				return HttpResponse('No hay resultados')
		else:
			# Controlar el caso de que el cliente envíe una petición vacía
			return HttpResponse('Por favor, introduce términos de búsqueda')

La vista primero determina el tipo de petición. Si es una petición POST, extraerá de ella los términos de búsqueda. Si hay al menos uno, filtrará las entradas de la base de datos en busca de ese término y luego, entre los resultados, en busca del resto de los términos. Si se obtienen resultados, los devuelve al cliente. En cualquier otro caso, se devuelve un mensaje de error al usuario.

Este código es, por desgracia, incompatible con ciertas características de seguridad de Django, por lo que tendremos que cambiar nuestra configuración para poder ejecutarlo. Concretamente, necesitamos deshabilitar la protección CSRF. En la próxima entrada, cuando refinemos nuestro uso de las respuestas, podremos volver a la configuración segura. Hecha esta advertencia, procedamos. Editamos el fichero SQproject/settings.py y comentamos la línea que activa el middleware de protección CSRF:

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',
]

Nunca debemos hacer esto en un entorno de producción. Lo hacemos aquí para mantener el código de la vista simple (Haz lo que digo, no lo que hago).

Finalmente, añadimos una entrada en SQproject/urls.py:

from django.conf.urls import url
from django.contrib import admin
from HWapp.views import randomquote, buscarCita

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^cita/', citaAleatoria),
    url(r'^buscar/', buscarCita),
]

Hemos añadido también buscarCita a las importaciones.

Y ya está. Activamos el servidor de desarrollo ejecutando python manage.py runserver y accediendo a http://127.0.0.1:8000/buscar/. Ya podemos buscar en nuestra colección de citas que contengan cierta palabra. Con este sencillo ejemplo, hemos cubierto la funcionalidad total de una aplicación interactiva que sirve datos respondiendo a peticiones concretas; no muy distinta a una base de datos. Al hacer esto, hemos cometido dos pecados: hemos deshabilitado parte de la seguridad de Django, y hemos incluido código HTML en nuestra vista (violando el principio modelo-vista-controlador). Ambos problemas se resolverán en la siguiente entrada, cuando veamos cómo usar plantillas de respuesta.

Deja una respuesta

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