Django middleware

El middleware de Django es un hook que modifica los objetos request o response de Django. Puede entenderse como un proceso de manejo intermedio entre HttpRequest y HttpResponse.

En el proceso del navegador desde la solicitud hasta la respuesta, Django necesita pasar por muchos middleware para procesar, como se muestra en la siguiente figura:

Funciones del middleware de Django:

  • Modificar la solicitud, es decir, el objeto HttpRequest que se transmite a la vista.
  • Modificar la respuesta, es decir, el objeto HttpResponse que devuelve la vista.

Los componentes del middleware se configuran en la lista de opciones MIDDLEWARE del archivo settings.py.

Cada opción de cadena en la configuración es una clase, es decir, un middleware.

Configuración de middleware predeterminada de Django:

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

Middleware personalizado

El middleware puede definir cuatro métodos, que son:

process_request(self,request)
process_view(self, request, view_func, view_args, view_kwargs)
process_exception(self, request, exception)
process_response(self, request, response)

Pasos para personalizar el middleware:

Cree un nuevo archivo py en el directorio de la app, con el nombre que desee, e importe MiddlewareMixin en ese archivo py:

from django.utils.deprecation import MiddlewareMixin

La clase de middleware personalizado debe heredar de la clase padre MiddlewareMixin:

class MD1(MiddlewareMixin): 
    pass
Registre la clase de middleware personalizado en MIDDLEWARE dentro de settings.py:
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
   
    'app01.middlewares.MD1',
]

Métodos de la clase de middleware personalizado

Los métodos de la clase de middleware personalizado son: process_request y process_response.

Método process_request

El método process_request tiene un parámetro request; este request es el mismo que el request en la función de vista.

El valor de retorno del método process_request puede ser None o un objeto HttpResponse.

  • Si el valor de retorno es None, continúa con el flujo normal y se pasa al siguiente middleware para su procesamiento.
  • Si el valor de retorno es un objeto HttpResponse, Django no ejecutará los métodos que se ejecutan antes de la función de vista posterior ni la función de vista; directamente, tomando este middleware como punto de partida, ejecuta los middleware en orden inverso, y ejecuta los métodos que se ejecutan después de la función de vista.

El método process_request se ejecuta antes de la función de vista.

Cuando se configuran varios middleware, se ejecutan en orden según el orden de registro en MIDDLEWARE, es decir, el valor del índice de la lista.

El parámetro request que se pasa entre diferentes middleware es el mismo objeto de solicitud.

Ejemplo

from django.utils.deprecation import MiddlewareMixin

from django.shortcuts import render, HttpResponse

class MD1(MiddlewareMixin):
    def process_request(self, request):
       print("md1 método process_request.", id(request)) #Se ejecuta antes de la vista

process_response

El método process_response tiene dos parámetros: uno es request y otro es response. request es el objeto de solicitud y response es el objeto HttpResponse devuelto por la función de vista. Este método debe tener un valor de retorno, y debe ser response.

El método process_response se ejecuta después de la función de vista.

Cuando se configuran varios middleware, se ejecutan en orden inverso según el orden de registro en MIDDLEWARE, es decir, el valor del índice de la lista.

Ejemplo

class MD1(MiddlewareMixin):
    def process_request(self, request):
        print("md1 método process_request.", id(request)) #Se ejecuta antes de la vista


    def process_response(self,request, response): :#Basado en solicitud-respuesta
        print("md1 método process_response!", id(request)) #Después de la vista
        return response

Como se ve en la siguiente figura, en circunstancias normales se ejecuta siguiendo la ruta verde; supongamos queel middleware 1tiene un valor de retorno, entonces se sigue la ruta roja, se ejecuta directamente el método process_response de esa clase y se retorna; los demás middleware posteriores no se ejecutarán.

process_view

El formato del método process_view es el siguiente:

process_view(request, view_func, view_args, view_kwargs)
El método process_view tiene cuatro parámetros:

  • request es el objeto HttpRequest.
  • view_func es la función de vista que Django está a punto de utilizar.
  • view_args es la lista de argumentos posicionales que se pasarán a la vista.
  • view_kwargs es el diccionario de argumentos de palabra clave que se pasarán a la vista.

view_args y view_kwargs no incluyen el primer parámetro de la vista (request).

El método process_view se ejecuta antes de la función de vista y después del método process_request.

El valor de retorno puede ser None, view_func(request) o un objeto HttpResponse.

  • Si el valor de retorno es None, continúa con el flujo normal y se pasa al siguiente middleware para su procesamiento.
  • Si el valor de retorno es un objeto HttpResponse, Django no ejecutará los métodos que se ejecutan antes de la función de vista posterior ni la función de vista; directamente, tomando este middleware como punto de partida, ejecuta los middleware en orden inverso, y ejecuta los métodos que se ejecutan después de la función de vista.
  • c. Si el valor de retorno es view_func(request), Django no ejecutará los métodos que se ejecutan antes de la función de vista posterior, ejecutará la función de vista de antemano, y luego ejecutará en orden inverso los métodos que se ejecutan después de la función de vista.
  • Cuando el process_request del último middleware llega al mapeo de rutas, regresa al process_view del primer middleware, y luego baja secuencialmente hasta llegar a la función de vista.

    Ejemplo

    class MD1(MiddlewareMixin):
        def process_request(self, request):
            print("md1 método process_request.", id(request)) #Se ejecuta antes de la vista


        def process_response(self,request, response): :#Basado en solicitud-respuesta
            print("md1 método process_response!", id(request)) #Después de la vista
            return response


        def process_view(self,request, view_func, view_args, view_kwargs):
            print("md1 método process_view!") #Se ejecuta antes de la vista, en orden
            #return view_func(request)

    process_exception

    El método process_exception es el siguiente:

    process_exception(request, exception)

    Descripción de parámetros:

    • request es el objeto HttpRequest.
    • exception es el objeto Exception generado por una excepción en la función de vista.

    El método process_exception solo se ejecuta si ocurre una excepción en la función de vista, y se ejecuta en orden inverso según el registro en settings.

    Se ejecuta después de la función de vista y antes del método process_response.

    El valor de retorno del método process_exception puede ser None o un objeto HttpResponse.

    Si el valor de retorno es None, la página reportará un error de código de estado 500 y la función de vista no se ejecutará.

    El método process_exception se ejecuta en orden inverso, y luego el método process_response se ejecuta también en orden inverso.

    Si el valor de retorno es un objeto HttpResponse, la página no reportará error y devolverá el código de estado 200.

    La función de vista no se ejecuta, los métodos process_exception posteriores de ese middleware tampoco se ejecutan, y se comienza a ejecutar directamente desde el método process_response del último middleware en orden inverso.

    Si el método process_view devuelve la función de vista, la función de vista se ejecuta de antemano y la función de vista reporta un error, entonces, sin importar cuál sea el valor de retorno del método process_exception, la página reportará un error, y ni la función de vista ni el método process_exception se ejecutarán.

    Se comienza a ejecutar directamente desde el método process_response del último middleware en orden inverso:

    Ejemplo

    class MD1(MiddlewareMixin):
        def process_request(self, request):
            print("md1 método process_request.", id(request)) #Se ejecuta antes de la vista

        def process_response(self,request, response): :#Basado en solicitud-respuesta
            print("md1 método process_response!", id(request)) #Después de la vista
            return response

        def process_view(self,request, view_func, view_args, view_kwargs):
            print("md1 método process_view!") #Se ejecuta antes de la vista, en orden
            #return view_func(request)


        def process_exception(self, request, exception):#Este método solo se activa si se produce un error
            print("md1 método process_exception!")
            # return HttpResponse(exception) #Devuelve la información del error

    Otras extensiones