Comprendre les Middlewares en Django

1. Fonctoinnalités des Middlewares Django

Manipuler les requêtes, c'est-à-dire l'objet HttpRequest transmis aux vues.
Modifier les réponses, c'est-à-dire l'objet HttpResponse retourné par les vues.

2. Les cinq méthodes de middleware

process_request☆

   1. process_request
        1. Moment d'exécution
            Avant la fonction de vue
        2. Paramètres
            request est le même objet que dans la vue
        3. Valeur de retour
            Retourne None  
            Retourne un objet HttpResponse   
                Ne exécute pas les méthodes process_request des middlewares suivants
                Ne exécute pas la vue
                Exécute directement la méthode process_response du middleware courant
        4. Ordre d'exécution
            Suivant l'ordre d'enregistrement
 
La méthode process_request a un paramètre request, qui est le même objet que celui utilisé dans la fonction de vue.

Elle peut retourner None ou un objet HttpResponse.

Si elle retourne None, le flux normal se poursuit avec le middleware suivant.
Si elle retourne un objet HttpResponse, Django n'exécutera pas les méthodes suivantes ni la vue, mais commencera à exécuter en ordre inverse les méthodes post-vue à partir de ce middleware.
La méthode process_request s'exécute avant la fonction de vue.

Lors de plusieurs middlewares configurés, ils s'exécutent dans l'ordre d'enregistrement dans MIDDLEWARE.

L'objet request est partagé entre tous les middlewares.

Exemple de code :
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import render, HttpResponse

class MonMiddleware(MiddlewareMixin):
    def process_request(self, requete):
       print("Méthode process_request du middleware 1.", id(requete)) #S'exécute avant la vue

process_view

    process_view
        1. Moment d'exécution
            Après process_request et avant la fonction de vue
        2. Paramètres
            requete est un objet HttpRequest.
            vue_func est la fonction de vue que Django va utiliser.
            vue_args est une liste des arguments positionnels passés à la vue.
            vue_kwargs est un dictionnaire des arguments de mots-clés passés à la vue.
            vue_args et vue_kwargs n'incluent pas le premier paramètre (requete).
        3. Valeur de retour
            Retourne  None  pour exécution normale 
            Retourne  un objet response pour sauter les middlewares suivants et la vue
            Retourne  vue_func(requete) pour exécuter immédiatement la vue puis continuer avec les méthodes post-vue
            
        4. Ordre d'exécution
            Suivant l'ordre d'enregistrement
            
La méthode process_view s'exécute après process_request et avant la fonction de vue.
Lorsque le dernier middleware process_request atteint la correspondance d'URL, il retourne au premier middleware process_view, puis continue séquentiellement jusqu'à la fonction de vue.

Exemple de code :
class MonMiddleware(MiddlewareMixin):
    def process_request(self, requete, callback, callback_args, callback_kwargs):
        #callback est la fonction de vue
        print("Méthode process_request du middleware 1.", id(requete))


    def process_response(self, requete, response): :#basé sur la requête/réponse
        print("Méthode process_response du middleware 1 !", id(requete)) #Après la vue
        return response


    def process_view(self, requete, vue_func, vue_args, vue_kwargs):
        print("Méthode process_view du middleware 1 !") #Avant la vue, exécution séquentielle
        #return vue_func(requete)

process_template_response

    process_template_response(déclenché conditionnellement: si la réponse de la vue a une méthode render)
        1. Moment d'exécution
            Après la fonction de vue, avant process_response
        2. Paramètres
        3. Valeur de retour
            Retourne un objet response
        4. Ordre d'exécution
            En ordre inverse d'enregistrement, après exécution de tous les process_template_response, la méthode response.render est appelée

process_exception

 process_exception(déclenché conditionnellement: en cas d'erreur)
                1. Moment d'exécution
                    Après la fonction de vue, avant process_response
                2. Paramètres
                    exception est l'objet d'erreur
                3. Valeur de retour
                    Retourne  None  pour ne pas gérer l'erreur, laissant le middleware suivant s'en occuper
                    Retourne  un objet response pour sauter les autres process_exception et exécuter directement tous les process_response
                4. Ordre d'exécution
                    En ordre inverse d'enregistrement
                    
Exemple de code :
class MonMiddleware(MiddlewareMixin):
    def process_request(self, requete):
        print("Méthode process_request du middleware 1.", id(requete))

    def process_response(self, requete, response):
        print("Méthode process_response du middleware 1 !", id(requete))
        return response

    def process_view(self, requete, vue_func, vue_args, vue_kwargs):
        print("Méthode process_view du middleware 1 !")
        #return vue_func(requete)


    def process_exception(self, requete, exception):#déclenché en cas d'erreur
        print("Méthode process_exception du middleware 1 !")
        # return HttpResponse(exception) #retourne le message d'erreur

process_response☆

 process_response    
        1. Moment d'exécution    
            Après la fonction de vue
        2. requete, response
            requete est le même objet que dans la vue
            response est l'objet response retourné
        3. Valeur de retour
            Retourne un objet response
        4. Ordre d'exécution
            En ordre inverse d'enregistrement
Exemple de code :
class MonMiddleware(MiddlewareMixin):
    def process_request(self, requete):
        print("Méthode process_request du middleware 1.", id(requete))

    def process_response(self, requete, response):
        print("Méthode process_response du middleware 1 !", id(requete))
        return response

Toutes ces méthodes peuvent retourner None ou un objet HttpResponse. Si None, l'exécution continue selon les règles de Django. Si HttpResponse, cet objet est directement retourné à l'utilisateur.

Lorsqu'un utilisateur envoie une requête, elle traverse tous les middlewares dans l'ordre d'enregistrement via la méthode process_request, atteint finalement la vue, puis revient à travers les middlewares via process_response avant d'être retournée à l'utilisateur.

3. Applications des méthodes de middleware

process_request peut faire quoi ?
	- Créer un middleware pour garantir que les données POST sont accessibles dans request.data quelle que soit l'encodage utilisée par le frontend
    - Limiter la fréquence d'accès (par exemple: une adresse IP ne peut accéder que 5 fois par minute)
    - Authentification (redirection vers la page de connexion si l'utilisateur n'est pas connecté)
    - Enregistrement des journaux d'accès utilisateur (IP, heure, chemin d'accès)
    
process_response peut faire quoi ? (a accès à l'objet response)
    - Ajouter des cookies à toutes les réponses (ou à certaines routes)
    - Ajouter des en-têtes de réponse à toutes les réponses (ou à certaines routes)
    
process_view (exécuté après correspondance de route et avant la fonction de vue)
    def process_view(self, requete, callback, callback_args, callback_kwargs):
            # print(callback)
            # print(callback_args)
            # print(callback_kwargs)
            #Effectuer des actions avant l'exécution de la fonction
            res=callback(requete)
            #Effectuer des actions après l'exécution de la fonction, similaire à un décorateur
            print("Process_view du middleware 1")
            return res    
    
process_exception (exécuté en cas d'erreur dans la vue, pour la gestion globale des exceptions)
    # Gestion globale des exceptions, retourne des réponses avec code d'erreur 4xx
    def process_exception(self, requete, exception):
        print(exception)
        return render(requete,'erreur.html')

4. Flux d'exécution des middlewares

1. Exécution de toutes les méthodes request jusqu'à atteindre la fonction de vue.
2. Exécution des autres méthodes du middleware.
3. Passage par toutes les méthodes response avant de retourner la réponse au client.

Note : Si un middleware retourne une valeur dans sa méthode request, seule sa méthode response correspondante est exécutée, puis la réponse est retournée à l'utilisateur. Les middlewares suivants ne sont pas exécutés.

5. Étapes pour créer un middleware personnalisé

	- Créer une classe qui hérite de MiddlewareMixin #from django.utils.deprecation import MiddlewareMixin
    - Implémenter les méthodes nécessaires comme process_request
    - Configurer dans settings (l'ordre d'enregistrement est important)
    	MIDDLEWARE = [
            ...
    		'mon_app.mon_middleware.MonMiddleware1',
            ...
		]  

Étiquettes: Django middleware python-web request-response web-development

Publié le 2 août à 06h51