title:      Rédaction de votre première appli Django, partie 3 : Création des vues de l&#39;interface publique
slug:       redaction-de-votre-premiere-appli-django-partie-3-creation-des-vues-de-l-interface-publique
date:       2006-06-17 19:41:58
type:       post
vignette:   images/logos/django.png
contextual_title1:  Le langage de template Django : Pour les auteurs de templates
contextual_url1:    20060815-le-langage-de-template-django-pour-les-auteurs-de-templates
contextual_title2:  Comparaison de TurboGears et Django, deux frameworks web Python
contextual_url2:    20060715-comparaison-de-turbogears-et-django-deux-frameworks-web-python
contextual_title3:  Rédaction de votre première appli Django, partie 4 : Conception d&#39;un formulaire et vues génériques
contextual_url3:    20060617-redaction-de-votre-premiere-appli-django-partie-4-conception-d-un-formulaire-et-vues-generiques

<p>Ce tutoriel commence là où s'est achevé le <a class="reference" href="https://larlet.fr/david/biologeek/archives/20060617-redaction-de-votre-premiere-appli-django-partie-2-exploration-de-l-interface-d-admin-auto-generee/">Tutoriel 2</a>. Nous continuons
l'application Web de sondage et allons nous focaliser sur la création
d'interfaces publiques -- les « vues ».</p>

<div class="section">
<h1><a id="philosophie" name="philosophie">Philosophie</a></h1>
<p>Une vue est un « type » de page Web dans votre application Django qui en général
sert une fonctionnalité spécifique et possède un template spécifique. Par
exemple, dans une application de weblog, vous pourriez avoir les vues suivantes:</p>
<blockquote>
<ul class="simple">
<li>Page d'accueil du blog -- afficher quelques unes des dernières entrées.</li>
<li>Page de « détail » d'un billet -- page au lien permanent pour un certain
billet.</li>
<li>Page d'archivage par années -- affiche tous les mois ayant des entrées
dans une année donnée.</li>
<li>Page d'archivage par mois -- affiche tous les jours ayant des entrées dans
un mois donné.</li>
<li>Page d'archivage par jour -- affiche toutes les entrées pour un jour
donné.</li>

<li>Action de commentaire -- gère l'envoi de commentaires pour un billet
donné.</li>
</ul>
</blockquote>
<p>Dans notre application de sondage, nous aurons les quatre vues suivantes:</p>
<blockquote>
<ul class="simple">
<li>Page « d'archive » des sondages -- affiche quelques uns des derniers
sondages.</li>
<li>Page « de détail » de sondage -- affiche la question d'un sondage, sans
les résultats mais avec un formulaire pour voter.</li>
<li>Page « de résultat » de sondage -- affiche les résultats pour un sondage
particulier.</li>
<li>Action de vote -- gère le vote d'un choix particulier pour un sondage
particulier.</li>
</ul>

</blockquote>
<p>Dans Django, chaque vue est représentée par une simple fonction Python.</p>
</div>
<div class="section">
<h1><a id="conception-de-vos-urls" name="conception-de-vos-urls">Conception de vos URLs</a></h1>
<p>La première étape dans la rédaction de vues est de concevoir la structure de vos
URLs. Vous faites cela en créant un module Python, appelé URLconf. Les URLconfs
décrivent comment Django associe une URL donnée avec un code Python donné.</p>
<p>Lorsqu'un utilisateur effectue une requête pour une page gérée par Django, le
système examine l'option <tt class="docutils literal"><span class="pre">ROOT_URLCONF</span></tt>, qui contient une chaîne dans la
syntaxe à points de Python. Django charge ce module et recherche une variable de
module appelé <tt class="docutils literal"><span class="pre">urlpatterns</span></tt>, que est une séquence de tuples dans le format
suivant:</p>
<pre class="literal-block">
(expression rationnelle, fonction Python de rappel [, dictionnaire facultatif])

</pre>
<p>Django démarre la première expression rationnelle et parcourt la liste, en
comparant l'URL de la requête avec chaque expression rationnelle jusqu'à ce
qu'il en trouve une qui corresponde.</p>
<p>Quand il trouve une correspondance, Django appelle la fonction Python de rappel,
avec un objet <tt class="docutils literal"><span class="pre">HTTPRequest</span></tt> en premier argument, toutes les valeurs
« capturées » dans l'expression rationnelle sous forme d'arguments mot-clés, et,
facultativement, un argument mot-clé arbitraire contenant un dictionnaire (le
troisième élément facultatif du tuple).</p>
<p>Pour plus d'infos sur les objets <tt class="docutils literal"><span class="pre">HTTPRequest</span></tt>, lisez la <a class="reference" href="http://www.djangoproject.com/documentation/request_response/">documentation sur
les requêtes et réponses</a>.
Pour plus de détails sur les URLconfs, lisez la <a class="reference" href="http://www.djangoproject.com/documentation/url_dispatch/">documentation URLconf</a>.</p>
<p>Quand vous avez lancé <tt class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">startproject</span> <span class="pre">monsite</span></tt> au début du
Tutoriel 1, ça a créé un URLconf par défaut dans <tt class="docutils literal"><span class="pre">monsite/urls.py</span></tt>. Ça a aussi
défini automatiquement votre option <tt class="docutils literal"><span class="pre">ROOT_URLCONF</span></tt> pour pointer vers ce
fichier:</p>

<pre class="literal-block">
ROOT_URLCONF = 'monsite.urls'
</pre>
<p>Passons à un exemple. Éditez <tt class="docutils literal"><span class="pre">monsite/urls.py</span></tt> pour qu'il ressemble à ceci:</p>
<pre class="literal-block">
from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^polls/$', 'monsite.polls.views.index'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/$', 'monsite.polls.views.detail'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/results/$', 'monsite.polls.views.results'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/vote/$', 'monsite.polls.views.vote'),
)
</pre>

<p>Cela mérite quelques explications. Lorsque quelqu'un effectue une requête sur
une page de votre site Web -- disons, « /polls/23/ », Django va charger ce
module Python, parce qu'il est pointé par l'option <tt class="docutils literal"><span class="pre">ROOT_URLCONF</span></tt>. Ça trouve
la variable nommée <tt class="docutils literal"><span class="pre">urlpatterns</span></tt> et parcourt les expressions rationnelles dans
l'ordre. Quand il trouve une expression rationnelle qui correspond --
<tt class="docutils literal"><span class="pre">r'^polls/(?P&lt;poll_id&gt;\d+)/$'</span></tt> -- il charge le module ou paquetage Python
associé : <tt class="docutils literal"><span class="pre">monsite.polls.views.detail</span></tt>. Ce qui correspond à la fonction
<tt class="docutils literal"><span class="pre">detail()</span></tt> dans <tt class="docutils literal"><span class="pre">mysite/polls/views.py</span></tt>.</p>

<p>Enfin, il appelle cette fonction <tt class="docutils literal"><span class="pre">detail()</span></tt> comme ceci:</p>
<blockquote>
detail(request=&lt;HttpRequest object&gt;, poll_id='23')</blockquote>
<p>La partie <tt class="docutils literal"><span class="pre">poll_id='23'</span></tt> vient de <tt class="docutils literal"><span class="pre">(?P&lt;poll_id&gt;\d+)</span></tt>. Mettre les parenthèses
autour d'un masque (pattern) « capture » le texte correspondant à ce masque et
l'envoie en argument à la fonction de vue. Le <tt class="docutils literal"><span class="pre">?P&lt;poll_id&gt;</span></tt> définit le nom qui
sera utilisé pour identifier le masque correspondant et <tt class="docutils literal"><span class="pre">\d+</span></tt> est une
expression rationnelle pour trouver une séquence de chiffres (c'est-à-dire, un
nombre).</p>

<p>Parce que les masques d'URL sont des expressions rationnelles, il n'y a vraiment
aucune limite sur ce que vous pouvez faire avec eux. Et il n'est pas nécessaire
d'ajouter de fioritures à l'URL tel que <tt class="docutils literal"><span class="pre">.php</span></tt> -- sauf si vous avez un sens de
l'humour tordu, dans lequel cas vous pouvez faire quelque chose comme ça:</p>
<pre class="literal-block">
(r'^polls/latest\.php$', 'monsite.polls.views.index'),
</pre>
<p>Mais, ne faites pas ça. C'est stupide.</p>
<p>Notez que ces expressions rationnelles ne recherchent pas dans les paramètres
GET et POST, ni dans le nom de domaine. Par exemple, dans une requête vers
<tt class="docutils literal"><span class="pre">http://www.exemple.com/monappli/</span></tt>, l'URLconf va rechercher dans
<tt class="docutils literal"><span class="pre">/monappli/</span></tt>. Dans une requête vers
<tt class="docutils literal"><span class="pre">http://www.exemple.com/monappli/?page=3</span></tt>, l'URLconf va rechercher dans

<tt class="docutils literal"><span class="pre">/myapp/</span></tt>.</p>
<p>Si vous avez besoin d'aide sur les expressions rationnelles, lisez <a class="reference" href="http://en.wikipedia.org/wiki/Regular_expression">l'article de
Wikipedia</a> et la <a class="reference" href="http://www.python.org/doc/current/lib/module-re.html">documentation Python</a>. De plus, le livre O'Reilly
« Mastering Regular Expressions » de Jeffrey Friedl est fantastique.</p>
<p>Pour finir, une note sur la performance: ces expressions rationnelles sont
compilées la première fois que le modul URLconf est chargé. Ça les rend très
rapides.</p>
</div>
<div class="section">
<h1><a id="crire-votre-premi-re-vue" name="crire-votre-premi-re-vue">Écrire votre première vue</a></h1>
<p>Bien, nous n'avons toujours pas créé de vue -- nous avons juste touché à
URLconf. Mais assurons-nous que Django suit l'URLconf comme il faut.</p>

<p>Lancez le serveur Web de développement de Django:</p>
<pre class="literal-block">
python manage.py runserver
</pre>
<p>Maintenant, allez sur « <a class="reference" href="http://localhost:8000/polls/">http://localhost:8000/polls/</a> » avec votre navigateur
Web. Vous devriez obtenir une page d'erreur agréablement colorée avec
le message suivant:</p>
<pre class="literal-block">
ViewDoesNotExist at /polls/

Tried index in module mysite.polls.views. Error was: 'module'
object has no attribute 'index'
</pre>
<p>Cette erreur survient parce que vous n'avez pas écrit la fonction <tt class="docutils literal"><span class="pre">index()</span></tt>
dans le module <tt class="docutils literal"><span class="pre">monsite/polls/views.py</span></tt>.</p>

<p>Essayez « /polls/23/ », « /polls/23/results/ » et « /polls/23/vote/ ». Les
messages d'erreur vous disent quelle vue Django essaie de charger (et n'arrive
pas à trouver, parce que vous n'avez pas encore écrit les vues).</p>
<p>Il est temps d'écrire la première vue. Ouvrez le fichier
<tt class="docutils literal"><span class="pre">monsite/polls/views.py</span></tt> et mettez-y le code Python suivant:</p>
<pre class="literal-block">
from django.http import HttpResponse

def index(request):
    return HttpResponse(&quot;Bonjour tout le monde. Vous est dans l'index des sondages.&quot;)
</pre>
<p>Voilà la vue la plus simple possible. Allez dans « /polls/ » avec votre
navigateur, et vous devriez voir votre texte.</p>
<p>À présent, ajoutez la vue suivante. C'est un petit peu différent, parce qu'il
prend un argument (qui, rappelez-vous, est passé depuis ce qui a été capturé par
l'expression rationnelle dans l'URLconf):</p>
<pre class="literal-block">

def detail(request, poll_id):
    return HttpResponse(&quot;Vous consultez le sondage %s.&quot; % poll_id)
</pre>
<p>Jetez à oeil à votre navigateur, à « /polls/34/ ». Ça affichera l'ID que vous
avez fournie dans l'URL.</p>
</div>
<div class="section">
<h1><a id="crire-des-vues-qui-font-quelque-chose" name="crire-des-vues-qui-font-quelque-chose">Écrire des vues qui font quelque chose</a></h1>
<p>Chaque vue a la responsabilité de faire l'une des deux choses suivantes :
Retourner un objet <tt class="docutils literal"><span class="pre">HttpResponse</span></tt> renfermant le contenu de la page demandée,
ou lever une exception telle que <tt class="docutils literal"><span class="pre">Http404</span></tt>. Le reste est pour vous.</p>

<p>Votre vue peut lire ou non les enregistrements d'une base de données. Il peut
utiliser ou non un système de template tel que celui de Django -- ou un système
tiers de template Python. Il peut générer un fichier PDF, une sortie XML, créer
un fichier ZIP à la volée, tout ce que vous voulez, en utilisant toutes les
bibliothèques Python que vous désirez.</p>
<p>Tout ce que Django veut, c'est <tt class="docutils literal"><span class="pre">HttpResponse</span></tt>. Ou une exception.</p>
<p>Parce que c'est plus pratique, utilisons l'API de base de données propre à
Django, que nous avons abordée dans le Tutoriel 1.  Voici un premier jet de la
vue <tt class="docutils literal"><span class="pre">index()</span></tt>, qui affiche les 5 dernières questions de sondage du système,
séparées par des virgules, triées par date de publication:</p>
<pre class="literal-block">
from monsite.polls.models import Poll
from django.http import HttpResponse

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    output = ', '.join([p.question for p in latest_poll_list])
    return HttpResponse(output)
</pre>
<p>Nous avons ici un problème, à savoir : Le design de la page est codée en dure
dans la vue. Si vous voulez changer l'apparence de la page, vous devrez éditer
ce code Python. Donc utilisons plutôt le système de template de Django pour
la présentation des données:</p>
<pre class="literal-block">
from django.template import Context, loader
from monsite.polls.models import Poll
from django.http import HttpResponse

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    t = loader.get_template('polls/index.html')
    c = Context({
        'latest_poll_list': latest_poll_list,
    })
    return HttpResponse(t.render(c))

</pre>
<p>Ce code charge la template appelé « polls/index.html » et lui passe un contexte.
Le contexte est un dictionnaire indexant les objets Python selon des noms de
variable de template.</p>
<p>Rechargez la page. Maintenant, vous verrez une erreur:</p>
<pre class="literal-block">
TemplateDoesNotExist at /polls/
polls/index.html
</pre>
<p>Ah. Il n'y a pas encore de template. En premier lieu, créez un répertoire,
quelque part dans votre système de fichers, auquel Django a accès (Django
s'exécute avec les droits de l'utilisateur qui a lancé le serveur). Cependant,
ne les mettez pas à la racine de vos documents. Vous ne devriez probablement pas
les rendre publics, juste par mesure de sécurité.</p>
<p>Puis éditez <tt class="docutils literal"><span class="pre">TEMPLATE_DIRS</span></tt> dans votre <tt class="docutils literal"><span class="pre">settings.py</span></tt> pour dire à Django où
il peut trouver les templates -- tout comme vous l'avez fait dans la section
« Personnaliser l'apparence de l'interface d'admin » du Tutoriel 2.</p>

<p>Une fois fait, créez un répertoire <tt class="docutils literal"><span class="pre">polls</span></tt> dans votre répertoire de templates.
Dedans, créez un fichier appelé <tt class="docutils literal"><span class="pre">index.html</span></tt>. Notez que notre code
<tt class="docutils literal"><span class="pre">loader.get_template('polls/index.html')</span></tt> ci-dessus se réfère à
&quot;[répertoire_de_templates]/polls/index.html&quot; dans le système de fichiers.</p>
<p>Placez le code suivant dans ce template:</p>
<pre class="literal-block">
{% if latest_poll_list %}
    &lt;ul&gt;

    {% for poll in latest_poll_list %}
        &lt;li&gt;{{ poll.question }}&lt;/li&gt;
    {% endfor %}
    &lt;/ul&gt;
{% else %}
    &lt;p&gt;Aucun sondage disponnible.&lt;/p&gt;
{% endif %}
</pre>

<p>Chargez la page dans votre navigateur Web, et vous devriez voir une liste à puce
contenant le sondage &quot;Quoi de neuf&quot; du Tutoriel 1.</p>
<div class="section">
<h2><a id="un-raccourci-render-to-response" name="un-raccourci-render-to-response">Un raccourci: render_to_response()</a></h2>
<p>Il est vraiment très courant de charger un template, remplir un contexte et
retourner un objet <tt class="docutils literal"><span class="pre">HttpResponse</span></tt> avec le résultat du rendu de la template.
Django fournit un raccourci. Voici le vue complète de <tt class="docutils literal"><span class="pre">index()</span></tt>, réécrite:</p>
<pre class="literal-block">
from django.shortcuts import render_to_response
from monsite.polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')
    return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})

</pre>
<p>Notez que nous n'avons plus besoin d'importer <tt class="docutils literal"><span class="pre">loader</span></tt>, <tt class="docutils literal"><span class="pre">Context</span></tt> ni
<tt class="docutils literal"><span class="pre">HttpResponse</span></tt>.</p>
<p>La fonction <tt class="docutils literal"><span class="pre">render_to_response()</span></tt> prend un nom de template en premier
argument et un dictionnaire comme second argument facultatif. Il retourne un
objet <tt class="docutils literal"><span class="pre">HttpResponse</span></tt> du template donné rendu avec le contexte donné.</p>

</div>
</div>
<div class="section">
<h1><a id="lever-l-erreur-404" name="lever-l-erreur-404">Lever l'erreur 404</a></h1>
<p>À présent, abordons la vue de sondage détaillé -- la page qui affiche la
question d'un sondage donné. Voici la vue:</p>
<pre class="literal-block">
from django.http import Http404
# ...
def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404
    return render_to_response('polls/detail.html', {'poll': p})
</pre>
<p>Le nouveau concept ici : La vue lève l'exception <tt class="docutils literal"><span class="pre">django.http.Http404</span></tt> si un
sondage avec l'ID demandé n'existe pas.</p>
<div class="section">
<h2><a id="un-raccourci-get-object-or-404" name="un-raccourci-get-object-or-404">Un raccourci : get_object_or_404()</a></h2>

<p>Il est vraiment très courant d'utiliser <tt class="docutils literal"><span class="pre">get_object()</span></tt> et de déclencher
<tt class="docutils literal"><span class="pre">Http404</span></tt> si l'objet n'existe pas. Django fournit un raccourci. Voici la vue
<tt class="docutils literal"><span class="pre">detail()</span></tt>, réécrite:</p>
<pre class="literal-block">
from django.shortcuts import render_to_response, get_object_or_404
# ...
def detail(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/detail.html', {'poll': p})
</pre>
<p>La fonction <tt class="docutils literal"><span class="pre">get_object_or_404()</span></tt> prend un modèle Django en premier argument
et un nombre arbitaire d'arguments mot-clés, qu'elle passe à la fonction

<tt class="docutils literal"><span class="pre">get_object()</span></tt> du module. Elle déclenche <tt class="docutils literal"><span class="pre">Http404</span></tt> si l'object n'existe pas.</p>
<div class="admonition-philosophie admonition">
<p class="first admonition-title">Philosophie</p>
<p>Pourquoi utilisons-nous une fonction utilitaire <tt class="docutils literal"><span class="pre">get_object_or_404()</span></tt> au
lieu de récupérer automatiquement les exceptions <tt class="docutils literal"><span class="pre">DoesNotExist</span></tt> de haut
niveau, ou avoir l'API du modèle qui déclenche <tt class="docutils literal"><span class="pre">Http404</span></tt> au lieu de

<tt class="docutils literal"><span class="pre">DoesNotExist</span></tt> ?</p>
<p class="last">Parce que ça serait coupler la couche du modèle avec la couche de la vue.
Une des règles d'or de la conception de Django est de maintenir ce
découplage entre les différentes couches.</p>
</div>
<p>Il y a également une fonction <tt class="docutils literal"><span class="pre">get_list_or_404()</span></tt>, qui fonctionne
similairement à <tt class="docutils literal"><span class="pre">get_object_or_404()</span></tt> -- sauf qu'elle utilise <tt class="docutils literal"><span class="pre">filter()</span></tt>
au lieu de <tt class="docutils literal"><span class="pre">get()</span></tt>. Elle lève <tt class="docutils literal"><span class="pre">Http404</span></tt> si la liste est vide.</p>

</div>
</div>
<div class="section">
<h1><a id="crire-une-vue-404-page-non-trouv-e" name="crire-une-vue-404-page-non-trouv-e">Écrire une vue 404 (page non trouvée)</a></h1>
<p>Lorsque vous levez une <tt class="docutils literal"><span class="pre">Http404</span></tt> à partir d'une vue, Django va charger une vue
spéciale qui s'occupe des erreurs 404. Il la trouve en cherchant la variable
<tt class="docutils literal"><span class="pre">handler404</span></tt>, qui est une chaîne de caractères utilisant la syntaxe Python à
points -- le même format qui est utilisé par l'URLconf. Une vue 404 en elle-même
n'a rien de particulier : c'est juste une vue classique.</p>
<p>Vous n'avez normalement pas à vous soucier de l'écriture des vues 404.
Par défaut les URLconfs ont la ligne suivante en en-tête :</p>
<blockquote>
from django.conf.urls.defaults import *</blockquote>

<p>Cela permet de prendre en compte le paramètre <tt class="docutils literal"><span class="pre">handler404</span></tt> pour le module
courrant. Comme vous pouvez le constater dans <tt class="docutils literal"><span class="pre">django/conf/urls/defaults.py</span></tt>,
<tt class="docutils literal"><span class="pre">handler404</span></tt> correspond par défaut à
<tt class="docutils literal"><span class="pre">'django.views.defaults.page_not_found'</span></tt>.</p>
<p>Encore trois remarques au sujet des vues 404 :</p>
<blockquote>
<ul class="simple">
<li>La vue 404 est aussi appelée si aucune des expressions rationnelle de
l'URLconf ne correspond à l'adresse demandée.</li>

<li>Si vous ne définissez pas votre propre vue 404 -- et utilisez celle par
défaut, ce qui est recommandé -- vous devez quand même créer un template
<tt class="docutils literal"><span class="pre">404.html</span></tt> à la racide de votre dossier de templates.</li>
<li>Si <tt class="docutils literal"><span class="pre">DEBUG</span></tt> est à <tt class="docutils literal"><span class="pre">True</span></tt> (dans votre module de paramètres), votre vue
404 utilisera ce template pour toutes les erreurs 404.</li>
</ul>
</blockquote>
</div>
<div class="section">

<h1><a id="crire-une-vue-500-erreur-serveur" name="crire-une-vue-500-erreur-serveur">Écrire une vue 500 (erreur serveur)</a></h1>
<p>De la même manière, URLconfs peut définir une <tt class="docutils literal"><span class="pre">handler500</span></tt>, qui pointe sur une
vue appelée en cas d'erreur du serveur. Les erreurs du serveur lorsque vous avez
des erreurs d'exécution dans le code de vos vues.</p>
</div>
<div class="section">
<h1><a id="utiliser-le-syst-me-de-template" name="utiliser-le-syst-me-de-template">Utiliser le système de template</a></h1>
<p>Revenons à notre vue <tt class="docutils literal"><span class="pre">polls.detail</span></tt>. Considérant la variable de contexte
<tt class="docutils literal"><span class="pre">poll</span></tt>, voici le template tel qu'il pourrait être:</p>
<pre class="literal-block">

&lt;h1&gt;{{ poll.question }}&lt;/h1&gt;
&lt;ul&gt;
{% for choice in poll.choice_set.all %}
    &lt;li&gt;{{ choice.choice }}&lt;/li&gt;
{% endfor %}
&lt;/ul&gt;
</pre>
<p>Le système de template utilise une syntaxe par points pour accéder aux attributs
des variables. Dans l'exemple <tt class="docutils literal"><span class="pre">{{</span> <span class="pre">poll.question</span> <span class="pre">}}</span></tt>, Django commence par
chercher la clé <tt class="docutils literal"><span class="pre">question</span></tt> du dictionnaire <tt class="docutils literal"><span class="pre">poll</span></tt>. N'y parvenant pas, il
essaye avec les attributs de classe -- ce qui marche dans ce cas. Si ça n'avait
pas été le cas, il aurait essayé d'appeler la méthode <tt class="docutils literal"><span class="pre">question()</span></tt> de l'objet
poll.</p>

<p>L'appel d'une méthode se produit dans la boucle <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">for</span> <span class="pre">%}</span></tt> :
<tt class="docutils literal"><span class="pre">poll.choice_set.all</span></tt> est interprété comme le code <tt class="docutils literal"><span class="pre">poll.choice_set.all()</span></tt>,
ce qui renvoie un iterable d'objets « Choice » ce qui est parfait pour une
utilisation dans un tag <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">for</span> <span class="pre">%}</span></tt>.</p>

<p>Lisez le <a class="reference" href="http://www.djangoproject.com/documentation/templates/">guide des templates</a> pour davantage de détails sur le fonctionnement
des templates.</p>
</div>
<div class="section">
<h1><a id="simplifier-urlconfs" name="simplifier-urlconfs">Simplifier URLconfs</a></h1>
<p>Prennons le temps de jouer un peu avec les vues et le système de templates. Lors
de l'édition d'URLconf, vous avez dû vous rendre compte de la redondance
présente dans le fichier:</p>
<pre class="literal-block">
urlpatterns = patterns('',
    (r'^polls/$', 'mysite.polls.views.index'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/$', 'mysite.polls.views.detail'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/results/$', 'mysite.polls.views.results'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/vote/$', 'mysite.polls.views.vote'),
)

</pre>
<p>Le répertoire d'accès <tt class="docutils literal"><span class="pre">mysite.polls.views</span></tt> est dans chaque URL.</p>
<p>Étant un cas courrant, le framework URLconf possède un raccourci pour les
préfixes communs. Vous pouvez les factoriser et les placer en premier argument
de <tt class="docutils literal"><span class="pre">patterns()</span></tt> de la façon suivante:</p>
<pre class="literal-block">
urlpatterns = patterns('mysite.polls.views',
    (r'^polls/$', 'index'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/$', 'detail'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/results/$', 'results'),
    (r'^polls/(?P&lt;poll_id&gt;\d+)/vote/$', 'vote'),
)

</pre>
<p>C'est identique au précédent formatage. C'est juste un peu plus propre.</p>
</div>
<div class="section">
<h1><a id="d-coupler-urlconfs" name="d-coupler-urlconfs">Découpler URLconfs</a></h1>
<p>En parlant de ça, prennons le temps de découpler les URLs de notre appli de
sondage à partir de la configuration de notre projet Django. Les applis Django
sont censées être « pluggables » -- ce qui signifie que chaque application peut
être transférée sur une autre installation de Django avec le minimum de
désagréments.</p>
<p>Notre appli de sondage est pas mal découplée pour le moment grâce à la structure
générée par <tt class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">startapp</span></tt>. Une partie est néanmois liée aux
paramètres de Django : l'URLconf.</p>

<p>Nous avons édité les URLs dans <tt class="docutils literal"><span class="pre">mysite/urls.py</span></tt>, mais la conception des URLs
d'une appli est spécifique à l'application, pas à l'installation de Django --
déplaçons donc les URLs dans le dossier de notre appli.</p>
<p>Copiez le fichier <tt class="docutils literal"><span class="pre">mysite/urls.py</span></tt> vers <tt class="docutils literal"><span class="pre">mysite/polls/urls.py</span></tt>. Puis,
modifiez <tt class="docutils literal"><span class="pre">mysite/urls.py</span></tt> pour retirer les URLs spécifiques au sondage et
insérez un <tt class="docutils literal"><span class="pre">include()</span></tt>:</p>
<pre class="literal-block">

(r'^polls/', include('mysite.polls.urls')),
</pre>
<p><tt class="docutils literal"><span class="pre">include()</span></tt>, permet simplement d'établir une référence à une autre URLconf.
Notez l'absence de <tt class="docutils literal"><span class="pre">$</span></tt> (détection de fin de chaîne de caractère) dans
l'expression rationnelle mais la présence d'un slash final. Lorsque Django
rencontre un <tt class="docutils literal"><span class="pre">include()</span></tt>, il extrait tout ce qui suit l'URL détectée et
l'envoie à l'URLconf inclus pour un traitement ultérieur.</p>
<p>Voici ce qu'il se passe si un utilisateur se rend sur « /polls/34/ » avec ce
système :</p>
<ul class="simple">
<li>Django va rencontrer <tt class="docutils literal"><span class="pre">'^polls/'</span></tt></li>
<li>Il va enlever la partie reconnue (<tt class="docutils literal"><span class="pre">&quot;polls/&quot;</span></tt>) et envoyer le texte restant --

<tt class="docutils literal"><span class="pre">&quot;34/&quot;</span></tt> -- à l'URLconf monsite.polls.urls' pour un traitement ultérieur.</li>
</ul>
<p>Maitenant que le découplage est effectué, il est nécessaire de découpler
l'URLconf de 'monsite.polls.urls' en enlevant les préfixes « polls/ » à chaque
ligne:</p>
<pre class="literal-block">
urlpatterns = patterns('monsite.polls.views',
    (r'^$', 'index'),
    (r'^(?P&lt;poll_id&gt;\d+)/$', 'detail'),
    (r'^(?P&lt;poll_id&gt;\d+)/results/$', 'results'),
    (r'^(?P&lt;poll_id&gt;\d+)/vote/$', 'vote'),
)
</pre>
<p>L'idée derrière <tt class="docutils literal"><span class="pre">include()</span></tt> et le découplage d'URLconf est de faciliter
l'aspect plug-and-play des URLs. Maintenant que les sondages ont leur propre
URLconf, ils peuvent être placés à la suite de « /polls », ou de « /fun_polls »,
ou de « /content/polls », ou de n'importe quelle URL, et l'appli sera toujours
fonctionnelle.</p>

<p>Toute l'appli de sondage se base sur des URL relatives, non sur des URLs
absolues.</p>
<p>Lorsque vous avez assimilé l'écriture des vues, lisez la
<a class="reference" href="https://larlet.fr/david/biologeek/archives/20060617-redaction-de-votre-premiere-appli-django-partie-4-conception-d-un-formulaire-et-vues-generiques/">partie 4 de ce tutoriel</a> de façon à en apprendre plus sur la génération de
formulaires et les vues génériques.</p>
<p>Vous pouvez maintenant retourner à la <a class="reference" href="https://larlet.fr/david/biologeek/archives/20060617-traduction-francaise-de-la-documentation-de-django-le-framework-web-python/">page d'accueil des traductions de la
documentation de Django</a>.</p>
<p>Cette traduction correspond à la révision 3589 (post 0.95).</p>
</div>
