\chapter{URLs et espaces de noms}


La gestion des URLs permet \textbf{grosso modo} d'assigner une adresse paramétrée ou non à une fonction Python.
La manière simple consiste à modifier le fichier \texttt{gwift/settings.py} pour y ajouter nos correspondances.
Par défaut, le fichier ressemble à ceci:

\begin{minted}{python}
# gwift/urls.py

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
]
\end{minted}


La variable \texttt{urlpatterns} associe un ensemble d'adresses à des fonctions.
Dans le fichier \textbf{nu}, seul le \textbf{pattern} \texttt{admin} est défini, et inclut toutes les adresses qui sont définies dans le fichier \texttt{admin.site.urls}.

Django fonctionne avec des \textbf{expressions rationnelles} simplifiées (des \textbf{expressions régulières} ou \textbf{regex}) pour trouver une correspondance entre une URL et la fonction qui recevra la requête et retournera une réponse.
Nous utilisons l'expression \texttt{\^{}\$} pour déterminer la racine de notre application, mais nous pourrions appliquer d'autres regroupements (\texttt{/home}, \texttt{users/\textless{}profile\_id\textgreater{}}, \texttt{articles/\textless{}year\textgreater{}/\textless{}month\textgreater{}/\textless{}day\textgreater{}}, \ldots\hspace{0pt}).
Chaque \textbf{variable} déclarée dans l'expression régulière sera apparenté à un paramètre dans la fonction correspondante. Ainsi, pour reprendre l'exemple où nous étions restés:

\begin{minted}{python}
# gwift/urls.py

from django.conf.urls import include, url
from django.contrib import admin

from wish import views as wish_views

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^$', wish_views.wishlists, name='wishlists'),
]
\end{minted}

Dans la mesure du possible, essayez toujours de \textbf{nommer} chaque expression.
Cela permettra notamment de les retrouver au travers de la fonction \texttt{reverse}, mais permettra également de simplifier vos templates.

A présent, on doit tester que l'URL racine de notre application mène bien vers la fonction \texttt{wish\_views.wishlists}.

Sauf que les pages \texttt{about} et \texttt{help} existent également. Pour implémenter ce type de précédence, il faudrait implémenter les URLs de la manière suivante:

\begin{verbatim}
| about
| help
| <user>
\end{verbatim}

Mais cela signifie aussi que les utilisateurs \texttt{about} et \texttt{help} (s'ils existent\ldots\hspace{0pt}) ne pourront jamais accéder à leur profil.
Une dernière solution serait de maintenir une liste d'authorité des noms d'utilisateur qu'il n'est pas possible d'utiliser.

D'où l'importance de bien définir la séquence de déinition de ces routes, ainsi que des espaces de noms.

Note sur les namespaces.

De là, découle une autre bonne pratique: l'utilisation de \emph{breadcrumbs} (\url{https://stackoverflow.com/questions/826889/how-to-implement-breadcrumbs-in-a-django-template}) ou de guidelines de navigation.


\section{Reverse}

En associant un nom ou un libellé à chaque URL, il est possible de récupérer sa \textbf{traduction}. Cela implique par contre de ne plus toucher à ce libellé par la suite\ldots\hspace{0pt}

Dans le fichier \texttt{urls.py}, on associe le libellé \texttt{wishlists} à l'URL \texttt{r\textquotesingle{}\^{}\$} (c'est-à-dire la racine du site):

\begin{minted}{python}
from wish.views import WishListList

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^$', WishListList.as_view(), name='wishlists'),
]
\end{minted}

De cette manière, dans nos templates, on peut à présent construire un lien vers la racine avec le tags suivant:

\begin{minted}{html}
<a href="{% url 'wishlists' %}">{{ yearvar }} Archive</a>
\end{minted}

De la même manière, on peut également récupérer l'URL de destination pour n'importe quel libellé, de la manière suivante:

\begin{minted}{python}
from django.core.urlresolvers import reverse_lazy

wishlists_url = reverse_lazy('wishlists')
\end{minted}