Comments on: Explication de code: des mixins et des décorateurs de méthode pour Django http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/ Deux développeurs en vadrouille qui se sortent les doigts du code Wed, 05 Feb 2014 12:15:31 +0000 hourly 1 http://wordpress.org/?v=3.3.1 By: FoxMaSk http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1497 FoxMaSk Tue, 21 Aug 2012 23:51:37 +0000 http://sametmax.com/?p=1812#comment-1497 Superbe article, limpide,  pour le neophite que je suis. Ya pas à dire, quand on maîtrise son sujet il est facile de mettre en lumière les subtilités comme celles ci. Du coup ça serait cool effectivement d'avoir un crobar du worflow des CBV. Dans le cas d'une page d'un profil utilisateur,  Ça me  permettrait d'éclaircir comment, après avoir surchargé le model User, je gère la form et la view, pour prendre en compte ces nouvelles propriétés lors de la soumission du formulaire. Superbe article, limpide,  pour le neophite que je suis. Ya pas à dire, quand on maîtrise son sujet il est facile de mettre en lumière les subtilités comme celles ci. Du coup ça serait cool effectivement d’avoir un crobar du worflow des CBV. Dans le cas d’une page d’un profil utilisateur,  Ça me  permettrait d’éclaircir comment, après avoir surchargé le model User, je gère la form et la view, pour prendre en compte ces nouvelles propriétés lors de la soumission du formulaire.

]]>
By: Sam http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1496 Sam Tue, 21 Aug 2012 21:46:54 +0000 http://sametmax.com/?p=1812#comment-1496 @Guillaume: voilà. C'est le but de l'héritage: ne pas avoir à tout réécrire. @Guillaume: voilà. C’est le but de l’héritage: ne pas avoir à tout réécrire.

]]>
By: Sveetch http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1491 Sveetch Tue, 21 Aug 2012 19:04:04 +0000 http://sametmax.com/?p=1812#comment-1491 Très bonne explication, très didactique, juste pour mentionner que le code soumis en snippets provient de l'initiative django-braces : https://github.com/brack3t/django-braces Très bonne explication, très didactique, juste pour mentionner que le code soumis en snippets provient de l’initiative django-braces : https://github.com/brack3t/django-braces

]]>
By: Guillaume http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1490 Guillaume Tue, 21 Aug 2012 16:23:25 +0000 http://sametmax.com/?p=1812#comment-1490 Je pense avoir pigé, la version "lourde" (avec la batterie de méthodes) du dispatch est dans le parent... Je pense avoir pigé, la version “lourde” (avec la batterie de méthodes) du dispatch est dans le parent…

]]>
By: Sam http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1489 Sam Tue, 21 Aug 2012 16:10:25 +0000 http://sametmax.com/?p=1812#comment-1489 Là on tombe dans des considérations de POO, cf mon alerte en début d'article. Quand on fait: <pre lang="python">class MaView(ListView): pass</pre> MaView n'implémente pas dispatch, donc quand MaView.dispatch sera appelée, ListView.dispatch sera utilisé automatiquement. Quand on fait: <pre lang="python">class MaView(ListView): ... @method_decorator(login_required) def dispatch(self, *args, **kwargs): ... </pre> MaView implémente dispatch. Du coup tout le code du parent (dont nous avons vu l'importance dans le commentaire précédent), n'est pas appelé, et la vue ne peut pas marcher. D'où le super(), qui permet d'appeler à la fin le dispatch du parent: <pre lang="python"> class MaView(ListView): ... @method_decorator(login_required) def dispatch(self, *args, **kwargs): return super(ProtectedView, self).dispatch(*args, **kwargs)</pre> Dans le cas d'un mixin: <pre lang="python">class MaVue(PermissionsRequiredMixin, ListView): required_permissions = ( 'dealer.create_cocaine', 'dealer.delete_cocaine', )</pre> MaVue n'implémente PAS dispatch. Donc quand on appelle MaVue.dispatch, c'est le PermissionsRequiredMixin.dispatch qui est appelé. Qui heureusement appelle ListView.dispatch ce qui permet à la vue de marcher. Là on tombe dans des considérations de POO, cf mon alerte en début d’article.

Quand on fait:

class MaView(ListView):
    pass

MaView n’implémente pas dispatch, donc quand MaView.dispatch sera appelée, ListView.dispatch sera utilisé automatiquement.

Quand on fait:

class MaView(ListView):
    ...
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        ...

MaView implémente dispatch. Du coup tout le code du parent (dont nous avons vu l’importance dans le commentaire précédent), n’est pas appelé, et la vue ne peut pas marcher. D’où le super(), qui permet d’appeler à la fin le dispatch du parent:

class MaView(ListView):
    ...
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ProtectedView, self).dispatch(*args, **kwargs)

Dans le cas d’un mixin:

class MaVue(PermissionsRequiredMixin, ListView):
    required_permissions = (
        'dealer.create_cocaine',
        'dealer.delete_cocaine',
    )

MaVue n’implémente PAS dispatch. Donc quand on appelle MaVue.dispatch, c’est le PermissionsRequiredMixin.dispatch qui est appelé. Qui heureusement appelle ListView.dispatch ce qui permet à la vue de marcher.

]]>
By: Guillaume http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1488 Guillaume Tue, 21 Aug 2012 15:43:32 +0000 http://sametmax.com/?p=1812#comment-1488 Excellent, mais...! Pourquoi le dispatch du parent? La classe fille implémente aussi dispatch(). Je ne saisis pas la subtilité. Je vous ferai une statue quand j'aurai bien tout compris! Excellent, mais…! Pourquoi le dispatch du parent? La classe fille implémente aussi dispatch(). Je ne saisis pas la subtilité. Je vous ferai une statue quand j’aurai bien tout compris!

]]>
By: Sam http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1487 Sam Tue, 21 Aug 2012 15:28:07 +0000 http://sametmax.com/?p=1812#comment-1487 Voilà le code de la méthode dispatch: <pre lang="python"> def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed self.request = request self.args = args self.kwargs = kwargs return handler(request, *args, **kwargs)</pre> Le rôle de dispatch() est donc multiple: - appeler la méthode post() ou get() (ou head() ou option(), etc. car tous les verbes HTTP sont disponibles) de la vue selon le type de requête; - si le verbe HTTP n'est pas un verbe connu, appeler la méthode http_method_not_allowed(); - si le verbe HTTP fait parti des methodes interdites pour cette vue, appeler http_method_not_allowed(); - ajouter à l'instance courante de la vue les attributs request, args et kwargs. On appelle donc TOUJOURS la méthode dispatch du parent, car toutes ces étapes sont nécessaires, pour toute les vues. Typiquement, dans le cas d'une vue de formulaire, on aura toujours du GET (pour l'affichage du formulaire à vide) et du POST (pour l'envoie des données du formulaire), donc c'est toujours utile dans ce cas. C'est d'ailleurs exactement ce que fait la vue générique ProcessFormView: https://docs.djangoproject.com/en/1.4/ref/class-based-views/#processformview Mais même dans le cas hypothétique d'une vue qui n'accepte que POST (ce qui est dommage, HEAD étant un verbe HTTP très utilisé par les navigateurs WEB pour la gestion du cache), on souhaite quand même garder dispatch()car elle a un rôle de sécurité: elle appelle http_method_not_allowed pour tous les autres verbes HTTP. Sans compter que sans self.request et self.kwargs, on ne peut pas faire grand chose dans une CBV. Voilà le code de la méthode dispatch:

    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        self.request = request
        self.args = args
        self.kwargs = kwargs
        return handler(request, *args, **kwargs)

Le rôle de dispatch() est donc multiple:

- appeler la méthode post() ou get() (ou head() ou option(), etc. car tous les verbes HTTP sont disponibles) de la vue selon le type de requête;
- si le verbe HTTP n’est pas un verbe connu, appeler la méthode http_method_not_allowed();
- si le verbe HTTP fait parti des methodes interdites pour cette vue, appeler http_method_not_allowed();
- ajouter à l’instance courante de la vue les attributs request, args et kwargs.

On appelle donc TOUJOURS la méthode dispatch du parent, car toutes ces étapes sont nécessaires, pour toute les vues.

Typiquement, dans le cas d’une vue de formulaire, on aura toujours du GET (pour l’affichage du formulaire à vide) et du POST (pour l’envoie des données du formulaire), donc c’est toujours utile dans ce cas.

C’est d’ailleurs exactement ce que fait la vue générique ProcessFormView:

https://docs.djangoproject.com/en/1.4/ref/class-based-views/#processformview

Mais même dans le cas hypothétique d’une vue qui n’accepte que POST (ce qui est dommage, HEAD étant un verbe HTTP très utilisé par les navigateurs WEB pour la gestion du cache), on souhaite quand même garder dispatch()car elle a un rôle de sécurité: elle appelle http_method_not_allowed pour tous les autres verbes HTTP. Sans compter que sans self.request et self.kwargs, on ne peut pas faire grand chose dans une CBV.

]]>
By: Guillaume http://sametmax.com/explication-de-code-des-mixins-et-des-decorateurs-de-methode-pour-django/#comment-1486 Guillaume Tue, 21 Aug 2012 15:12:57 +0000 http://sametmax.com/?p=1812#comment-1486 Brillant l'article! J'ai suivi la mécanique de la démonstration globalement mais je me heurte à des questions métaphysiques! La fonction dispatch, pas de souci avec ses arguments extraits des URLs. Par contre un "zoom" sur sa finalité s'impose. Le dispatch, c'est l'aiguillage, le 2 en 1 du get et du post? True? Petite question : une soumission par un formulaire, je vais avoir du post. Est ce que le dispatch de la vue pourrait être géré une fonction post? je suppose que oui. Mais alors quelle est la finalité d'utiliser la fonction dispatch de la classe parent de la vue? Je crois que vos explications seront les bienvenue! Brillant l’article! J’ai suivi la mécanique de la démonstration globalement mais je me heurte
à des questions métaphysiques!
La fonction dispatch, pas de souci avec ses arguments extraits des URLs.
Par contre un “zoom” sur sa finalité s’impose.
Le dispatch, c’est l’aiguillage, le 2 en 1 du get et du post? True?
Petite question :
une soumission par un formulaire, je vais avoir du post. Est ce que le dispatch de la vue
pourrait être géré une fonction post? je suppose que oui.
Mais alors quelle est la finalité d’utiliser la fonction dispatch de la classe parent de la vue?
Je crois que vos explications seront les bienvenue!

]]>