Middlewares en Django



@eduardo_gpg

Número de visitas 5246

Tiempo de lectura 5 min

8 Septiembre 2020

Habrá ocasiones en las cuales será necesario ejecutar ciertas acciones, ya sea antes o después de cada petición, y para ello podemos apoyarnos del framework Middleware que Django nos ofrece. Es sin duda un tema muy interesante. 😎 Es por ello que en esta ocasión me gustaría habláramos acerca de los middlewares en Django, definiéramos exactamente qué son, cómo crearlos y por supuesto, cómo podemos sacarles el máximo provecho posible.

Bien, sin más introducción, pongamos manos a la obra.

Middlewares en Django

Comencemos con la pregunta obligada ¿Qué es un Middleware? verás, en términos simples podemos definir un Middlawere cómo una pieza de código la cual se ejecutará antes y/o después de cada petición realizada al servidor.

Lo interesante de los middlewares en Django es que estos tiene la posibilidad de modificar la petición antes que esta llegue a la vista, y claro antes que el template sea renderizado. Esto nos permite, no solo agregar funcionalidad extra a las vistas, si no poder realizar diferentes validaciones sobre cada una de las peticiones al servidor, ya sea con fines de seguridad o simple debug. 😲

Veamos un ejemplo. Para este post crearemos un Middleware el cual nos permita conocer la dirección IP del cliente, posteriormente validaremos si dicha IP se encuentra o no, dentro de una lista negra, si así negaremos el servicio retornando un error 404.

Para lograr esto dividiremos el post en tres partes.

  • Introducción
  • Middleware
  • Negación del servicio

En la parte introductoria crearemos y configuraremos nuestro proyecto. Si tú ya posee un proyecto puedes saltarte este paso.

Introducción.

Lo primero que haremos será un nuevo entorno de desarrollo. Para ello utilizamos el módulo venv.

python -m venv env

Una vez el entorno haya sido creado, procedemos a activarlo.

source env/bin/activate

Ahora toca el turno de instalar Django.

pip install django

Listo, procedamos a crear nuestra proyecto con su correspondiente aplicación.

$ django-admin startproject tutorial
$ cd tutorial
$ python manage.py startapp posts

Registramos nuestra aplicación en el proyecto.

INSTALLED_APPS = [
    ...,
    'posts',
]

Ahora creamos nuestra url principal. El archivo urls.py debería quedar algo así.

...
from posts.views import index

urlpatterns = [
    path('', index, name='index'),
     ...
]

Ya para finalizar creamos nuestra vista en el archivo views.py, esto para nuestra aplicación posts.

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hola mundo desde PyWomabt.")

La vista es algo bastante sencilla, únicamente retornamos un pequeño mensaje, pero para términos prácticos funcionara. 🧐

Si ejecutamos el servidor y nos situamos en http://localhost:8000/ obtendremos la siguiente respuesta.

Con lo cual confirmamos que nuestro proyecto esta ejecutandose de forma correctamente.

Middleware

Ok, ya tenemos el servidor funcionando, ahora procedamos a crear nuestro primer middleware, y para ello será necesario crear el archivo middleware.py. dentro de la aplicación posts.

En dicho archivo (middleware.py) colocamos las siguientes líneas de código.

def ip_is_valid(get_response):

    def middleware(request):
        # Código que se ejecutará antes del llamado a la vista.
        print('Hola mundo desde un Middleware!!!')
        response = get_response(request)
        # Código que se ejecutará después del llamado a la vista.
        return response

    return middleware

En este caso nuestro middleware posee por nombre ip_is_valid, puesto que su función será validar la dirección IP del cliente.

Es posible que te hayas percatado que el middleware no es más que un decorador; 😋 ya que recibe como argumento una función, posee una función anidada y retorna dicha función.

Ahora procesamos a registrar el middleware en el proyecto. Nos situamos en el archivo settings.py y modificamos el listado de middlewares.

MIDDLEWARE = [
    ...
    'post.middleware.ip_is_valid',
]

Perfecto, si realizamos todos los pasos de forma correcta al volver a realizar una petición sobre http://localhost:8000/ el mensaje Hola mundo desde un Middleware!!! deberá imprimirse en consola.

Aquí hay varios puntos a tener en cuenta.

  • 1.- Tenemos acceso a la petición a través del objeto request.
  • 2.- La función get_response será la encargada de ejecutar nuestra vista. Dicha función retorna lo que la vista retorne (Muy probablemente un template 🤓).
  • 3.- Mediante la función middleware seremos capaces de extender funcionalidades a nuestra vista, ya sea ejecutando código antes o después que la vista sea llamada.

Con todos estos conocimientos procedamos a obtener la dirección IP.

Para no hacer tan extenso el post (y complicado) me estaré apoyando de la librería ipware para obtener dicha dirección.

Procedemos a instalarla la librería.

pip install django-ipware

Una vez hecho esto, el middleware quedaría de la siguiente forma.

from ipware import get_client_ip

def ip_is_valid(get_response):

    def middleware(request):

        ip, is_routable = get_client_ip(request)

        print(ip)
        print(is_routable)

        return self.get_response(request)

    return middleware

Si ejecutamos y realizamos la petición dal servidor, deberíamos visualizar en consola, tanto la IP (Que en nuestro caso al encontrarnos en un ambiente de desarrollo será 127.0.0.1 (Localhost) ) y así mismos si la dirección IP se puede enrutar públicamente a Internet.

127.0.0.1
False

Negación del servicio

Cómo estamos trabajando de forma local ¿Qué te parece si baneamos las peticiones provenientes de localhost? 😬

from ipware import get_client_ip
from django.http import HttpResponse

BLACK_LIST = [
    '127.0.0.1'
]

def ip_is_valid(get_response):

    def middleware(request):

        ip, is_routable = get_client_ip(request)

        if ip in BLACK_LIST:
            return HttpResponse('Bad request', status=404)
        else:
            return get_response(request)

    return middleware

Para este ejemplo me apoyo de una lista negra de direcciones. Validamos sobre una sola dirección (localhost), sin embargo cuanto te encuentre en producción podrás colocar la n cantidad de direcciones beneadas. Si la dirección se encuentra dentro de ella retornamos un 404 al cliente.


Ahora, quizás te estes preguntando ¿Este Middleware funciona sobre todas las peticiones en el proyecto? y la respuesta es sí. Y esto es lo interesante de los middlewares, una vez que nosotros los registramos en el proyecto, estos actuarán para cada petición sobre cada URL; en extremo de utilidad si queremos testear o simplemente validar peticiones.

Algunos ejemplos en donde es una muy buena idea implementar un Middleware podrías ser: Para obtener la IP de la petición, validar un Access Tokens, Obtener zonas horarias, consumir API`s, crear o consular registros, crear o leer sesiones etc ... Hay una infinidad de ejemplos para los Middlewares.

Ahora, es importante mencionar que utilizar funciones no es la única forma de crear Middlewares, no, y de hecho otra forma de hacerlo es mediante clases. Utilizando clases tendremos una mayor flexibilidad sobre exactamente que vamos a ejecutar y cuándo.

Veamos un rápido ejemplo. Realicemos un refactor a nuestros decorador, ahora utilicemos clases.

from ipware import get_client_ip
from django.http import HttpResponse

BLACK_LIST = [
    '127.0.0.1'
]

class IPIsValid():
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        ip, is_routable = get_client_ip(request)

        if ip in BLACK_LIST:
            return HttpResponse('Bad request', status=404)
        else:
            return get_response(request)
MIDDLEWARE = [
    ...
    'post.middleware.IPIsValid',
]

Al nosotros utilizar un clase cómo Middleware, tendremos acceso a diferentes métodos con los cuales podremos ser mucho más puntales en indicar cuando queremos realizar una acción.

Alguno de los métodos son:

  • process_view
  • process_exception
  • process_template_response

De estos métodos ya estaremos hablando en una segunda , te invito a que le eches un vistazo. 😊

Bien, con esto estaríamos concluyendo el post en esta ocasión, en donde aprendimos exactamente qué es un Middleware, cómo podemos crearlos y cómo podemos utilizarlos.

Recordemos, un Middleware no es más que pieza de código que se ejecuta para cada una de las peticiones realizadas al servidor. A través de ellos seremos capaces de añadir funcionalidades de nuestras vistas; ya sea para condicionar o simplemente debugear. 🐍


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login

Más Tips y Ejercicios 🐍

Adquiere una subscripción PyWombat por tan solo $3 USD. al mes.

Conoce los beneficios de ser usuario premium:
Niveles desbloqueados: Ten accesos a todos los niveles de ejercicios. 🔓
Nuevo límite: Incrementa tu límite de ejercicios por semana. 🚀
Contenido único: Recibe semanalmente recursos exclusivos de Python (Videos, Artículos y Capitulos del libro PyWombat, comienza como desarrollador Python. 🐍