Quand l'utilisation de reverse est impossible

Quel est le problème ?

Dans un projet Django, il y a au moins 2 types de fichiers où l'utilisation de la fonction reverse est impossible les urls n'ayant pas encore été déterminées :

  • dans settings.py pour redéfinir un paramètre contenant une url. Exemple : LOGIN_URL,
  • dans un fichier urls.py pour passer une url à une view. Exemple : redéfinir l'url vers laquelle l'utilisateur est redirigé à la validation d'un formulaire.

La solution naïve

La solution naïve est d'écrire l'url en dur. Le problème est que, si la vue est déplacée sur une autre url, il sera nécessaire de modifier tous les endroits où elle a été définie.

Cette solution va à l'encontre du principe DRY (Don't Repeat Yourself) et introduira des erreurs si vous oubliez de modifier une url, ce qui est vite arrivé sur un gros projet ou dans une situation d'urgence.

Il exite bien sûr des moyens de limiter les dommages :

  • tester le code retour des vues avec des tests unitaire afin de détecter les erreurs 404 qui pourraient se produire,
  • dans le cas de la surchage d'un paramètre de fonction, il est possible de créer une nouvelle fonction dans le fichier views.py faisant appel à la fonction voulue avec en paramètre une url définie à l'aide de reverse.

Heureusement, il existe une solution simple de continuer à utiliser la beauté de reverse.

La solution paresseuse

En utilisant une fonction paresseuse (lazy en anglais) le calcul de l'url va être retardé jusqu'au moment où l'url est utilisée. A ce moment, tous les fichiers urls.py auront été lus et toutes les urls seront connues.

Django 1.2 ne propose pas de version paresseuse de la fonction reverse mais tout le nécessaire est disponible pour la construire. Un rapport de bug a été ouvert et la fonction lazy_reverse devrait faire son apparition dans Django 1.3.

En attendant, il suffit de procéder ainsi :

from django.core.urlresolvers import reverse
from django.utils.functional import lazy

lazy_reverse = lazy(reverse, str)

Il ne vous reste plus qu'à utiliser lazy_reverse en lieu et place de reverse dans vos fichiers settings.py et urls.py.

4 mai 2011 : Le ticket a été intégré à Django le 29 avril dans le changeset 16121, il fera partie de la future version 1.4 de Django.

social