Qu’est ce qu’un middleware Django ? 7


Vous savez qu’il y a un settings qui ressemble à ça:

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

Vous savez qu’il est important. Vous ne savez pas vraiment pourquoi.

WaT iZ a MideulWaire ?

Un middleware est un moyen d’éxécuter du code à toutes requêtes et/ou à toutes les réponses reçues et envoyées par Django. Si vous ne voyez pas comment fonctionne le cyle de requêtes/réponses, faites un petit saut sur notre schéma de fonctionnement général de Django.

Un middleware, c’est une classe Python ordinaire, avec deux méthodes: une appelée pour les requêtes, une appelée pour les réponses.

L’exemple bidon habituel

class MideulWaireForEverReturnsTheRevenge3(object):
 
    # cette méthode sera appelée automatiquement pour chaque requête
    # et Django lui passera la requête en cours
    def process_request(self, request):
        print "Hey, une requête est arrivée !"
        # on est pas obligé de retourner quoi que ce soit
 
    # cette méthode sera appelée automatiquement pour chaque réponse
    # et Django lui passera la reponse en cours et la requete
    # à laquelle on répond
    def process_response(self, request, response):
        print "Hey, on a répondu a une requête !"
        # on DOIT retourner une réponse
        return response

On met tout ça dans un fichier mon_projet/mon_app/middlewares.py, et on active le middleware en le rajoutant dans les settings:

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'mon_projet.mon_app.middlewares.MideulWaireForEverReturnsTheRevenge3'
)

Et à chaque reload de page, dans l’affichage du terminal de dev, on a ça:

Capture d'écran de l'output terminal de ./mange.py runserver avec un middleware qui print sur stdout

./manage.py runserver

Et voici ce qui se passe dans le fonctionnement de Django: il trouve la liste des classes de middlewares, et pour chaque requête et réponse, il appelle les méthodes process_response et process_request de chaque middleware.

Schéma de fonctionnement des middlewares en Django

C'est l'histoire de la viiiiiiiiiiiiiie. C'est le cycle éterneeeeeleuuuuuuuuuuuu

Les points les plus importants

Aucune méthode n’est obligatoire, vous pouvez créer un middleware avec uniquement l’une ou l’autre.

Si process_request renvoit une réponse, tout s’arrête. Les process_request des autres middlewares ne sont pas appelés, vos vues ne sont pas appelées, et c’est le cycle de réponse qui commence directement. Très utile si par exemple vous voulez faire une redirection brutale pour toutes les requêtes qui correspondent à un certain critère (par exemple rediriger vers un site mobile).

Les middlewares sont appelés dans leur ordre de déclaration dans MIDDLEWARE_CLASSES pour chaque requête, et dans l’ordre inverse pour chaque réponse. Mettez donc votre middleware au bon endroit dans la file: inutile de mettre un middleware qui vérifie si un user a des droits avant le middleware d’authentification, puisque l’utilisateur n’est pas encore authentifié.

Un middleware peut posséder 3 autres méthodes également facultatives: process_view (appelée juste avant l’appel de chaque vue, et et permettant de modifier l’instance de la vue elle-même), process_template_response (appelée sur chaque instance implémentant une méthode render, et surtout utilisée pour injecter des données dans TemplateResponse) et process_exception (appelée quand une vue lève une exception).

Pour quoi utiliser les middleware ?

Exemples de quelques middlewares qui viennent d’office avec Django:

  • UpdateCacheMiddleware, FetchFromCacheMiddleware: ils cachent l’intégralité des pages.
  • GZipMiddleware: retourne une réponse compressée si le browser le gère.
  • LocaleMiddleware: set la langue que Djando doit utiliser, en fonction du navigateur.
  • MessageMiddleware: gestion des “flash-messages”.
  • SessionMiddleware: gestion des sessions.
  • AuthenticationMiddleware: authentifier un utilisateur.

Il y en a beaucoup d’autres, et il y en a plein qui trainent sur internet. Mais bien entendu le plus chouette, c’est d’en faire un soi-même.

Par exemple, quand je développe (pas en prod, hien !), j’utilise souvent ce petit middleware que j’ai fait avec amour:

class ForceSuperUserMiddleWare(object):
    def process_request(self, request):
        request.user = User.objects.filter(is_superuser=True)[0]

Comme ça je suis toujours connecté en tant que super user, même sur les projets avec des timeout courts pour la session, des doubles authentifications super relous et tout le toutim des clients paranos (traduction: des américains).

7 thoughts on “Qu’est ce qu’un middleware Django ?

Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.