Benoît Bryon avatar Benoît Bryon committed c754417

Removed deprecated article about Django and reverse_lazy()

Comments (0)

Files changed (3)

    * `Organiser les répertoires d'un projet
      <../fr/articles/organisation-repertoires-projet-deploiement.html>`_
    * `Pourquoi documenter ? <../fr/articles/documentation.html>`_
-   * `Django et reverse() <../fr/articles/django-reverse-lazy.html>`_
 
 Elsewhere...
 ============

fr/articles/django-reverse-lazy.txt

-:lang: fr
-
-##############
-reverse_lazy()
-##############
-
-.. epigraph:: Quand django.core.urlresolvers.reverse() n'est pas applicable.
-
-
-*********
-Prérequis
-*********
-
-Afin d'aller à l'essentiel, je ne prendrai pas le temps d'expliciter toutes les 
-notions utilisées dans cet article. Aussi, si vous êtes mal à l'aise avec l'un 
-ou l'autre des concepts, voici quelques pistes de lecture :
-
-* `Django et les URL`_, et en particulier le passage à propos de `reverse()`_
-* `les "décorateurs" Python`_ et leur application aux vues Django, par exemple 
-  avec `le décorateur @login_required`_.
-
-.. _`Django et les URL`: http://docs.djangoproject.com/en/1.2/topics/http/urls/
-.. _`reverse()`: http://docs.djangoproject.com/en/1.2/topics/http/urls/#reverse
-.. _`les "décorateurs" Python`: http://www.gawel.org/howtos/python-decorators
-.. _`le décorateur @login_required`: http://docs.djangoproject.com/en/1.2/topics/auth/#the-login-required-decorator
-
-
-*********
-reverse()
-*********
-
-Dans le framework Django, la fonction reverse() 
-(django.core.urlresolvers.reverse pour être exact) est importante. La 
-`documentation Django à propos de reverse()`_ l'explique assez bien. Je ne 
-m'étendrai pas sur l'intérêt de cette fonction. Elle est tout bonnement 
-indispensable.
-
-.. _`documentation Django à propos de reverse()`: http://docs.djangoproject.com/en/1.2/topics/http/urls/#reverse
-
-Résumé du problème
-==================
-
-La fonction reverse() effectue une recherche dans les URLconf de Django. Plus 
-précisément, elle fait une recherche dans un objet URLResolver. Ce dernier  
-construit un catalogue à partir des URLconf.
-
-Donc, c'est bien logique, la fonction reverse() ne peut opérer que si le 
-catalogue des URLconf est prêt.
-
-Or, il y a des cas où reverse() est nécessaire alors que le catalogue d'URLconf 
-n'est pas encore construit.
-
-Pour faire simple, le catalogue d'URLconf est construit très tôt, mais beaucoup 
-de modules Python sont chargés encore plus tôt.
-
-Pour les curieux, regardez le code de 
-`django.core.handlers.base.BaseHandler.get_response()`_ pour vous faire  une 
-idée plus précise du moment où l'URLResolver est initialisé.
-
-.. _`django.core.handlers.base.BaseHandler.get_response()`: http://code.djangoproject.com/browser/django/tags/releases/1.2.3/django/core/handlers/base.py#L66
-
-reverse() dans les URLconf
-==========================
-
-Premier cas facile à appréhender : que se passe-t-il si on souhaite utiliser 
-reverse() dans une URLconf ?
-
-Pour lire le catalogue, on lit les URLconf.
-Si une URLconf utilise reverse(), alors on a besoin du catalogue.
-Or on est justement en train de le construire...
-
-Par exemple si l'on veut créer une redirection "en dur", on peut utiliser 
-django.views.generic.simple.redirect_to dans une URLconf. Cette vue requiert 
-un paramètre obligatoire, "url". Étant donné qu'il est hors de question 
-d'utiliser l'URL directement, on a besoin de reverse().
-
-reverse() dans les decorateurs de vues
-======================================
-
-C'est, d'après mon expérience personnelle, le cas le plus courant.
-
-On souhaite appliquer un décorateur à une vue. Ce décorateur prend un paramètre 
-qui est une URL. Pas question d'indiquer l'URL réelle. Alors on a besoin de 
-reverse().
-
-Pour bien comprendre pourquoi on ne peut pas utiliser reverse() ici, il faut 
-savoir que pour construire le catalogue d'URLconf, Django importe les vues 
-qui y sont mentionnées. Cela provoque l'interprétation du code de ces modules, 
-et l'exécution du code "global" dans ces modules. Les décorateurs sont 
-appliqués aux vues à ce moment-là.
-
-reverse() à d'autres endroits
-=============================
-
-Quelques autres emplacements méritent une attention particulière :
-
-* les fichiers __init__.py des modules listés dans INSTALLED_APPS
-* la configuration, dont le traditionnel settings.py
-
-Dans ces emplacements, et plus généralement dans beaucoup d'endroits où l'appel 
-à reverse() n'est pas encapsulé dans un objet ou une fonction, le problème 
-peut apparaître.
-
-
-****************************
-reverse_lazy(): une solution
-****************************
-
-Une solution simple à mettre en oeuvre est d'utiliser reverse_lazy(). Cette 
-fonction n'est pas encore disponible en standard dans Django.
-
-Le principe : ne pas procéder à la résolution d'URL immédiatemment, comme le 
-fait reverse(), mais le faire lorsque le résultat de la fonction est utilisé.
-
-Lors de la construction des URLconf, si reverse() était appelé, la résolution 
-d'URL serait tentée, mais son résultat ne serait pas utilisé. Lors de l'appel 
-de reverse_lazy(), la résolution d'URL n'est pas tentée. La résolution n'est 
-tentée que lorsqu'on utilise le résultat de reverse_lazy() en tant que chaîne 
-de caractères. Par exemple lorsqu'on l'utilise dans la vue redirect_to() pour 
-passer un header HTTP 302 redirect. Ou alors lorsqu'on l'affiche dans un 
-template avec {% url ... %}. Mais en aucun cas lorsqu'on contruit le catalogue 
-des URLconf. 
-
-Le ticket `Django #5925 <http://code.djangoproject.com/ticket/5925>`_ 
-fait ce constat et propose une implémentation de reverse_lazy(). Il semblerait 
-que le patch manque de tests unitaires pour être accepté.
-
-La solution préconisée dans le ticket sus-mentionnée utilise l'utilitaire 
-django.utils.functional.lazy(). Ce qui est très propre. Je ne l'ai pas encore 
-testée.
-
-Pour ma part, j'utilisais jusqu'à présent le code ci-dessous, directement 
-inspiré du `DjangoSnippet n°499 de guettli`_. Un des commentaires du ticket 
-utilise un principe similaire.
-
-.. _`DjangoSnippet n°499 de guettli`: http://www.djangosnippets.org/snippets/499/
-
-.. sourcecode:: python
-    
-    """
-    Lazy pattern applied to django.core.urlresolvers.reverse().
-    
-    Codebase from http://www.djangosnippets.org/snippets/499/ by guettli
-    Added support of the % operator, which is required to pass a LazyString   
-    to django.views.generic.simple.redirect_to().
-    """
-    from django.core.urlresolvers import reverse
-    
-    
-    class LazyString(object):
-        """A str-like object which value is computed when the object is actually 
-        used as a string.
-        """
-        def __init__(self, function, *args, **kwargs):
-            """Constructs a "lazy" str-like object.
-            
-            The call to "function" is delayed.
-            The "function" parameter receives any additional args only when the 
-            LazyString instance is used as a str.
-            """
-            self.function=function
-            self.args=args
-            self.kwargs=kwargs
-        
-        def __str__(self):
-            """Executes self.function to convert LazyString instance to a real 
-            str.""" 
-            if not hasattr(self, '_str'):
-                self._str=self.function(*self.args, **self.kwargs)
-            return self._str
-        
-        def __mod__(self, operand):
-            """Handles string formating operator."""
-            return self.__str__() % operand
-  
-  
-    def reverse_lazy(*args, **kwargs):
-        """Delays URL resolution to the moment when the returned value is used
-        as a string.
-        
-        Use it like Django's builtin reverse(), wherever reverse() cannot be 
-        called:
-        
-        * in URLconf
-        * in decorators of views
-        * everywhere parsed before Django's URL resolver is built. In doubt, 
-          everywhere outside functions and objects, including argument
-          definition of functions or methods.
-        """
-        return LazyString(reverse, *args, **kwargs)
-
-
-**********************
-Solutions alternatives
-**********************
-
-Pour aller plus loin dans la réflexion, voici quelques hypothèses...
-Notez bien qu'à ce jour, je ne sais pas si elles se vérifient.
-
-reverse() dans les URLconf
-==========================
-
-Si les vues ne prenaient pas en argument des URL "réelles" mais les paramètres 
-permettant de les obtenir, le problème ne se poserait pas. En effet, la 
-résolution des URL se ferait dans les vues, à un moment ou le catalogue 
-d'URLconf est déjà construit.
-
-Pour les URL internes, on l'a déjà dit, il est hors de question de ne pas 
-utiliser reverse(). Donc pour les URL internes, on pourrait passer à la vue les 
-paramètres qu'on passe à reverse() au lieu de passer le résultat.
-
-Pour les URL externes, on ne dispose pas d'un outil équivalent à reverse(). De 
-là à dire qu'on peut se permettre de passer des URL "en dur", il y a un pas que 
-je n'ose faire. En principe, ces URL ne devraient pas apparaître en dur dans 
-le code. Au pire, elles devraient être des variables de configuration. Dans la 
-mesure du possible, un équivalent à reverse() pour les URL externes serait donc 
-le bienvenu.
-
-Donc on pourrait imaginer passer les paramètres suivants aux vues :
-
-* la méthode pour obtenir l'URL. Par exemple "reverse" ou "external_reverse". 
-  Dans l'absolu, ce pourrait être n'importe quel callable ou adapter.
-* les paramètres à passer à cette méthode.
-
-reverse() dans les décorateurs de vues
-======================================
-
-On l'a évoqué, pour construire le catalogue d'URLconf, Django importe toutes 
-les vues qui y sont mentionnées.
-
-Si Django n'importait pas ces vues au moment de construire le catalogue 
-d'URLconf, le problème reverse() dans les fichiers views.py, hors des vues, ne 
-se poserait pas.
-
-Mais, pourraient s'écrier certains, il est nécessaire d'importer ces vues pour 
-"compiler" les URLconf. De façon à ne charger les vues qu'une seule fois. Pour 
-des raisons de performances.
-
-Au moins deux approches pourraient débouter cet argument :
-
-* construire le catalogue en deux temps. D'abord sans importer les vues. On 
-  peut alors obtenir la correspondance entre URL et URLpattern. C'est suffisant 
-  pour utiliser reverse(). Importons les vues à ce moment-là.
-
-* importer les vue en mode "lazy". C'est à dire importer les vues à la demande. 
-  Si une vue est demandée, l'importer et s'arranger pour que l'import ne se 
-  fasse plus. Mais ne pas importer les vues pour lesquelles le serveur ne 
-  reçoit aucune requête. En plus d'être une alternative à reverse_lazy(), cette 
-  solution pourrait faire économiser des ressources à un processus qui, durant 
-  sa vie, ne reçoit aucune requête sur certaines vues. Le gain serait d'autant 
-  plus grand que la vie d'un processus est courte, ou que le nombre de modules 
-  contenant des vues est grand.
-
-Une autre hypothèse serait de ne pas appliquer les décorateurs dans le même 
-module que les vues elles-mêmes. Cette approche me fait penser à d'autres 
-concepts, peut-être plus proches du monde Zope / Plone (que je ne connais pas 
-bien, soit dit en passant). Par exemple n'est-il pas pertinent de séparer la 
-vue en elle-même et ses "modificateurs" ? D'autres diraient "Adapter" il me 
-semble. En effet le décorateur @login_required ne devrait-il pas être appliqué 
-seulement si le site est configuré ainsi ? Peut-être que pour d'autres sites la 
-même vue pourrait être publique ? Ou bien le décorateur pourrait être une 
-version personnalisée du @login_required ? Découpler la logique des décorateurs 
-de celle des vues permettrait d'économiser du code (et par là-même des 
-erreurs). Mais, on touche peut-être là à des fondamentaux de Django.
 * :doc:`articles/canaliser-les-flux-de-communication`
 * :doc:`articles/organisation-repertoires-projet-deploiement`
 * :doc:`articles/documentation`
-* :doc:`articles/django-reverse-lazy`
 
 Ailleurs
 ========
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.