ajout d’un callback before_filter sur Django

J’ai l’habitude de travailler avec le Framework Ruby On Rails et il y a un filtre before_filter sur les contrôleurs qui permet d’exécuter un ensemble de taches avant de lancer une action. C’est utile pour si on veut vérifier qu’un utilisateur s’est bien connecté et a les droits d’exécuter une action par exemple.

Récemment, j’ai commencé à développer une application Django au bureau et je me suis rendu compte que cette fonctionnalité n’existe pas dans cet univers 🙁

Après l’avoir googlé je suis tombé sur un middleware qui permet de le faire sur Django 🙂 (encore merci M. Google).

Voici le middleware en question :

import sys

class BeforeFilterMiddleware(object):
    def __init__(self):
        self.setting = 'BEFORE_FILTER'
        self.filters = []

    def _call_filters(self, request, view, args, kwargs):
        response = None
        for f in self.filters:
            response = f(request, view, args, kwargs)
            if response and response.has_header('location'):
                self.filters = []
                return response
        self.filters = []
        return response

    def process_view(self, request, view, args, kwargs):
        module = sys.modules[view.__module__]
        if hasattr(module, self.setting):
            for func, views in getattr(module, self.setting).items():
                exclude = '-%s' % view.func_name
                if not views or view.func_name in views: # or views and exclude not in views:
                    if hasattr(module, func):
                        if getattr(module, func) not in self.filters:
                            self.filters.append(getattr(module, func))
        if self.filters:
            return self._call_filters(request, view, args, kwargs)
        return None

Utilisation :

J’ai enregistré ce script dans un fichier outils/my_middlewares/before_filter.py du répertoire principal de mon application.

Ensuite, je l’ai ajouté sur la liste des middlewares de mon application : la constante MIDDLEWARE_CLASSES du fichier de configuration settings.py, maintenant il doit ressembler à ca :

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',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'outils.my_middlewares.before_filter.BeforeFilterMiddleware',
)

C’est tout pour la configuration.

Maintenant si on veut, par exemple, exécuter une fonction admin_required avant de lancer les actions new et create et owner_required pour l’action edit il suffit d’ajouter ces lignes de code sur ladite view :

BEFORE_FILTER = {'admin_required': ('new', 'create'),
                 'owner_required': ('edit',),
                 }

def admin_required(request, view, args, kwargs):
    if not is_admin():
        messages.warning(request, u"Vous ne pouvez pas accéder à cette page")
        return HttpResponseRedirect(reverse('root'))

def owner_required(request, view, args, kwargs):
    if not is_owner():
        messages.warning(request, u"Vous ne pouvez pas modifier une ressource qui ne vous appartient pas")
        return HttpResponseRedirect(reverse('root'))

C’est tout ! Vous avez des questions ? Commentez 🙂