Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

article.md 31KB

5 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. title: Rédaction de votre première appli Django, partie 3 : Création des vues de l'interface publique
  2. slug: redaction-de-votre-premiere-appli-django-partie-3-creation-des-vues-de-l-interface-publique
  3. date: 2006-06-17 19:41:58
  4. type: post
  5. vignette: images/logos/django.png
  6. contextual_title1: Le langage de template Django : Pour les auteurs de templates
  7. contextual_url1: 20060815-le-langage-de-template-django-pour-les-auteurs-de-templates
  8. contextual_title2: Comparaison de TurboGears et Django, deux frameworks web Python
  9. contextual_url2: 20060715-comparaison-de-turbogears-et-django-deux-frameworks-web-python
  10. contextual_title3: Rédaction de votre première appli Django, partie 4 : Conception d'un formulaire et vues génériques
  11. contextual_url3: 20060617-redaction-de-votre-premiere-appli-django-partie-4-conception-d-un-formulaire-et-vues-generiques
  12. <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
  13. l'application Web de sondage et allons nous focaliser sur la création
  14. d'interfaces publiques -- les « vues ».</p>
  15. <div class="section">
  16. <h1><a id="philosophie" name="philosophie">Philosophie</a></h1>
  17. <p>Une vue est un « type » de page Web dans votre application Django qui en général
  18. sert une fonctionnalité spécifique et possède un template spécifique. Par
  19. exemple, dans une application de weblog, vous pourriez avoir les vues suivantes:</p>
  20. <blockquote>
  21. <ul class="simple">
  22. <li>Page d'accueil du blog -- afficher quelques unes des dernières entrées.</li>
  23. <li>Page de « détail » d'un billet -- page au lien permanent pour un certain
  24. billet.</li>
  25. <li>Page d'archivage par années -- affiche tous les mois ayant des entrées
  26. dans une année donnée.</li>
  27. <li>Page d'archivage par mois -- affiche tous les jours ayant des entrées dans
  28. un mois donné.</li>
  29. <li>Page d'archivage par jour -- affiche toutes les entrées pour un jour
  30. donné.</li>
  31. <li>Action de commentaire -- gère l'envoi de commentaires pour un billet
  32. donné.</li>
  33. </ul>
  34. </blockquote>
  35. <p>Dans notre application de sondage, nous aurons les quatre vues suivantes:</p>
  36. <blockquote>
  37. <ul class="simple">
  38. <li>Page « d'archive » des sondages -- affiche quelques uns des derniers
  39. sondages.</li>
  40. <li>Page « de détail » de sondage -- affiche la question d'un sondage, sans
  41. les résultats mais avec un formulaire pour voter.</li>
  42. <li>Page « de résultat » de sondage -- affiche les résultats pour un sondage
  43. particulier.</li>
  44. <li>Action de vote -- gère le vote d'un choix particulier pour un sondage
  45. particulier.</li>
  46. </ul>
  47. </blockquote>
  48. <p>Dans Django, chaque vue est représentée par une simple fonction Python.</p>
  49. </div>
  50. <div class="section">
  51. <h1><a id="conception-de-vos-urls" name="conception-de-vos-urls">Conception de vos URLs</a></h1>
  52. <p>La première étape dans la rédaction de vues est de concevoir la structure de vos
  53. URLs. Vous faites cela en créant un module Python, appelé URLconf. Les URLconfs
  54. décrivent comment Django associe une URL donnée avec un code Python donné.</p>
  55. <p>Lorsqu'un utilisateur effectue une requête pour une page gérée par Django, le
  56. système examine l'option <tt class="docutils literal"><span class="pre">ROOT_URLCONF</span></tt>, qui contient une chaîne dans la
  57. syntaxe à points de Python. Django charge ce module et recherche une variable de
  58. module appelé <tt class="docutils literal"><span class="pre">urlpatterns</span></tt>, que est une séquence de tuples dans le format
  59. suivant:</p>
  60. <pre class="literal-block">
  61. (expression rationnelle, fonction Python de rappel [, dictionnaire facultatif])
  62. </pre>
  63. <p>Django démarre la première expression rationnelle et parcourt la liste, en
  64. comparant l'URL de la requête avec chaque expression rationnelle jusqu'à ce
  65. qu'il en trouve une qui corresponde.</p>
  66. <p>Quand il trouve une correspondance, Django appelle la fonction Python de rappel,
  67. avec un objet <tt class="docutils literal"><span class="pre">HTTPRequest</span></tt> en premier argument, toutes les valeurs
  68. « capturées » dans l'expression rationnelle sous forme d'arguments mot-clés, et,
  69. facultativement, un argument mot-clé arbitraire contenant un dictionnaire (le
  70. troisième élément facultatif du tuple).</p>
  71. <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
  72. les requêtes et réponses</a>.
  73. 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>
  74. <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
  75. 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
  76. défini automatiquement votre option <tt class="docutils literal"><span class="pre">ROOT_URLCONF</span></tt> pour pointer vers ce
  77. fichier:</p>
  78. <pre class="literal-block">
  79. ROOT_URLCONF = 'monsite.urls'
  80. </pre>
  81. <p>Passons à un exemple. Éditez <tt class="docutils literal"><span class="pre">monsite/urls.py</span></tt> pour qu'il ressemble à ceci:</p>
  82. <pre class="literal-block">
  83. from django.conf.urls.defaults import *
  84. urlpatterns = patterns('',
  85. (r'^polls/$', 'monsite.polls.views.index'),
  86. (r'^polls/(?P&lt;poll_id&gt;\d+)/$', 'monsite.polls.views.detail'),
  87. (r'^polls/(?P&lt;poll_id&gt;\d+)/results/$', 'monsite.polls.views.results'),
  88. (r'^polls/(?P&lt;poll_id&gt;\d+)/vote/$', 'monsite.polls.views.vote'),
  89. )
  90. </pre>
  91. <p>Cela mérite quelques explications. Lorsque quelqu'un effectue une requête sur
  92. une page de votre site Web -- disons, « /polls/23/ », Django va charger ce
  93. module Python, parce qu'il est pointé par l'option <tt class="docutils literal"><span class="pre">ROOT_URLCONF</span></tt>. Ça trouve
  94. la variable nommée <tt class="docutils literal"><span class="pre">urlpatterns</span></tt> et parcourt les expressions rationnelles dans
  95. l'ordre. Quand il trouve une expression rationnelle qui correspond --
  96. <tt class="docutils literal"><span class="pre">r'^polls/(?P&lt;poll_id&gt;\d+)/$'</span></tt> -- il charge le module ou paquetage Python
  97. associé : <tt class="docutils literal"><span class="pre">monsite.polls.views.detail</span></tt>. Ce qui correspond à la fonction
  98. <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>
  99. <p>Enfin, il appelle cette fonction <tt class="docutils literal"><span class="pre">detail()</span></tt> comme ceci:</p>
  100. <blockquote>
  101. detail(request=&lt;HttpRequest object&gt;, poll_id='23')</blockquote>
  102. <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
  103. autour d'un masque (pattern) « capture » le texte correspondant à ce masque et
  104. 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
  105. sera utilisé pour identifier le masque correspondant et <tt class="docutils literal"><span class="pre">\d+</span></tt> est une
  106. expression rationnelle pour trouver une séquence de chiffres (c'est-à-dire, un
  107. nombre).</p>
  108. <p>Parce que les masques d'URL sont des expressions rationnelles, il n'y a vraiment
  109. aucune limite sur ce que vous pouvez faire avec eux. Et il n'est pas nécessaire
  110. 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
  111. l'humour tordu, dans lequel cas vous pouvez faire quelque chose comme ça:</p>
  112. <pre class="literal-block">
  113. (r'^polls/latest\.php$', 'monsite.polls.views.index'),
  114. </pre>
  115. <p>Mais, ne faites pas ça. C'est stupide.</p>
  116. <p>Notez que ces expressions rationnelles ne recherchent pas dans les paramètres
  117. GET et POST, ni dans le nom de domaine. Par exemple, dans une requête vers
  118. <tt class="docutils literal"><span class="pre">http://www.exemple.com/monappli/</span></tt>, l'URLconf va rechercher dans
  119. <tt class="docutils literal"><span class="pre">/monappli/</span></tt>. Dans une requête vers
  120. <tt class="docutils literal"><span class="pre">http://www.exemple.com/monappli/?page=3</span></tt>, l'URLconf va rechercher dans
  121. <tt class="docutils literal"><span class="pre">/myapp/</span></tt>.</p>
  122. <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
  123. 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
  124. « Mastering Regular Expressions » de Jeffrey Friedl est fantastique.</p>
  125. <p>Pour finir, une note sur la performance: ces expressions rationnelles sont
  126. compilées la première fois que le modul URLconf est chargé. Ça les rend très
  127. rapides.</p>
  128. </div>
  129. <div class="section">
  130. <h1><a id="crire-votre-premi-re-vue" name="crire-votre-premi-re-vue">Écrire votre première vue</a></h1>
  131. <p>Bien, nous n'avons toujours pas créé de vue -- nous avons juste touché à
  132. URLconf. Mais assurons-nous que Django suit l'URLconf comme il faut.</p>
  133. <p>Lancez le serveur Web de développement de Django:</p>
  134. <pre class="literal-block">
  135. python manage.py runserver
  136. </pre>
  137. <p>Maintenant, allez sur « <a class="reference" href="http://localhost:8000/polls/">http://localhost:8000/polls/</a> » avec votre navigateur
  138. Web. Vous devriez obtenir une page d'erreur agréablement colorée avec
  139. le message suivant:</p>
  140. <pre class="literal-block">
  141. ViewDoesNotExist at /polls/
  142. Tried index in module mysite.polls.views. Error was: 'module'
  143. object has no attribute 'index'
  144. </pre>
  145. <p>Cette erreur survient parce que vous n'avez pas écrit la fonction <tt class="docutils literal"><span class="pre">index()</span></tt>
  146. dans le module <tt class="docutils literal"><span class="pre">monsite/polls/views.py</span></tt>.</p>
  147. <p>Essayez « /polls/23/ », « /polls/23/results/ » et « /polls/23/vote/ ». Les
  148. messages d'erreur vous disent quelle vue Django essaie de charger (et n'arrive
  149. pas à trouver, parce que vous n'avez pas encore écrit les vues).</p>
  150. <p>Il est temps d'écrire la première vue. Ouvrez le fichier
  151. <tt class="docutils literal"><span class="pre">monsite/polls/views.py</span></tt> et mettez-y le code Python suivant:</p>
  152. <pre class="literal-block">
  153. from django.http import HttpResponse
  154. def index(request):
  155. return HttpResponse(&quot;Bonjour tout le monde. Vous est dans l'index des sondages.&quot;)
  156. </pre>
  157. <p>Voilà la vue la plus simple possible. Allez dans « /polls/ » avec votre
  158. navigateur, et vous devriez voir votre texte.</p>
  159. <p>À présent, ajoutez la vue suivante. C'est un petit peu différent, parce qu'il
  160. prend un argument (qui, rappelez-vous, est passé depuis ce qui a été capturé par
  161. l'expression rationnelle dans l'URLconf):</p>
  162. <pre class="literal-block">
  163. def detail(request, poll_id):
  164. return HttpResponse(&quot;Vous consultez le sondage %s.&quot; % poll_id)
  165. </pre>
  166. <p>Jetez à oeil à votre navigateur, à « /polls/34/ ». Ça affichera l'ID que vous
  167. avez fournie dans l'URL.</p>
  168. </div>
  169. <div class="section">
  170. <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>
  171. <p>Chaque vue a la responsabilité de faire l'une des deux choses suivantes :
  172. Retourner un objet <tt class="docutils literal"><span class="pre">HttpResponse</span></tt> renfermant le contenu de la page demandée,
  173. ou lever une exception telle que <tt class="docutils literal"><span class="pre">Http404</span></tt>. Le reste est pour vous.</p>
  174. <p>Votre vue peut lire ou non les enregistrements d'une base de données. Il peut
  175. utiliser ou non un système de template tel que celui de Django -- ou un système
  176. tiers de template Python. Il peut générer un fichier PDF, une sortie XML, créer
  177. un fichier ZIP à la volée, tout ce que vous voulez, en utilisant toutes les
  178. bibliothèques Python que vous désirez.</p>
  179. <p>Tout ce que Django veut, c'est <tt class="docutils literal"><span class="pre">HttpResponse</span></tt>. Ou une exception.</p>
  180. <p>Parce que c'est plus pratique, utilisons l'API de base de données propre à
  181. Django, que nous avons abordée dans le Tutoriel 1. Voici un premier jet de la
  182. vue <tt class="docutils literal"><span class="pre">index()</span></tt>, qui affiche les 5 dernières questions de sondage du système,
  183. séparées par des virgules, triées par date de publication:</p>
  184. <pre class="literal-block">
  185. from monsite.polls.models import Poll
  186. from django.http import HttpResponse
  187. def index(request):
  188. latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
  189. output = ', '.join([p.question for p in latest_poll_list])
  190. return HttpResponse(output)
  191. </pre>
  192. <p>Nous avons ici un problème, à savoir : Le design de la page est codée en dure
  193. dans la vue. Si vous voulez changer l'apparence de la page, vous devrez éditer
  194. ce code Python. Donc utilisons plutôt le système de template de Django pour
  195. la présentation des données:</p>
  196. <pre class="literal-block">
  197. from django.template import Context, loader
  198. from monsite.polls.models import Poll
  199. from django.http import HttpResponse
  200. def index(request):
  201. latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
  202. t = loader.get_template('polls/index.html')
  203. c = Context({
  204. 'latest_poll_list': latest_poll_list,
  205. })
  206. return HttpResponse(t.render(c))
  207. </pre>
  208. <p>Ce code charge la template appelé « polls/index.html » et lui passe un contexte.
  209. Le contexte est un dictionnaire indexant les objets Python selon des noms de
  210. variable de template.</p>
  211. <p>Rechargez la page. Maintenant, vous verrez une erreur:</p>
  212. <pre class="literal-block">
  213. TemplateDoesNotExist at /polls/
  214. polls/index.html
  215. </pre>
  216. <p>Ah. Il n'y a pas encore de template. En premier lieu, créez un répertoire,
  217. quelque part dans votre système de fichers, auquel Django a accès (Django
  218. s'exécute avec les droits de l'utilisateur qui a lancé le serveur). Cependant,
  219. ne les mettez pas à la racine de vos documents. Vous ne devriez probablement pas
  220. les rendre publics, juste par mesure de sécurité.</p>
  221. <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ù
  222. il peut trouver les templates -- tout comme vous l'avez fait dans la section
  223. « Personnaliser l'apparence de l'interface d'admin » du Tutoriel 2.</p>
  224. <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.
  225. Dedans, créez un fichier appelé <tt class="docutils literal"><span class="pre">index.html</span></tt>. Notez que notre code
  226. <tt class="docutils literal"><span class="pre">loader.get_template('polls/index.html')</span></tt> ci-dessus se réfère à
  227. &quot;[répertoire_de_templates]/polls/index.html&quot; dans le système de fichiers.</p>
  228. <p>Placez le code suivant dans ce template:</p>
  229. <pre class="literal-block">
  230. {% if latest_poll_list %}
  231. &lt;ul&gt;
  232. {% for poll in latest_poll_list %}
  233. &lt;li&gt;{{ poll.question }}&lt;/li&gt;
  234. {% endfor %}
  235. &lt;/ul&gt;
  236. {% else %}
  237. &lt;p&gt;Aucun sondage disponnible.&lt;/p&gt;
  238. {% endif %}
  239. </pre>
  240. <p>Chargez la page dans votre navigateur Web, et vous devriez voir une liste à puce
  241. contenant le sondage &quot;Quoi de neuf&quot; du Tutoriel 1.</p>
  242. <div class="section">
  243. <h2><a id="un-raccourci-render-to-response" name="un-raccourci-render-to-response">Un raccourci: render_to_response()</a></h2>
  244. <p>Il est vraiment très courant de charger un template, remplir un contexte et
  245. retourner un objet <tt class="docutils literal"><span class="pre">HttpResponse</span></tt> avec le résultat du rendu de la template.
  246. Django fournit un raccourci. Voici le vue complète de <tt class="docutils literal"><span class="pre">index()</span></tt>, réécrite:</p>
  247. <pre class="literal-block">
  248. from django.shortcuts import render_to_response
  249. from monsite.polls.models import Poll
  250. def index(request):
  251. latest_poll_list = Poll.objects.all().order_by('-pub_date')
  252. return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
  253. </pre>
  254. <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
  255. <tt class="docutils literal"><span class="pre">HttpResponse</span></tt>.</p>
  256. <p>La fonction <tt class="docutils literal"><span class="pre">render_to_response()</span></tt> prend un nom de template en premier
  257. argument et un dictionnaire comme second argument facultatif. Il retourne un
  258. objet <tt class="docutils literal"><span class="pre">HttpResponse</span></tt> du template donné rendu avec le contexte donné.</p>
  259. </div>
  260. </div>
  261. <div class="section">
  262. <h1><a id="lever-l-erreur-404" name="lever-l-erreur-404">Lever l'erreur 404</a></h1>
  263. <p>À présent, abordons la vue de sondage détaillé -- la page qui affiche la
  264. question d'un sondage donné. Voici la vue:</p>
  265. <pre class="literal-block">
  266. from django.http import Http404
  267. # ...
  268. def detail(request, poll_id):
  269. try:
  270. p = Poll.objects.get(pk=poll_id)
  271. except Poll.DoesNotExist:
  272. raise Http404
  273. return render_to_response('polls/detail.html', {'poll': p})
  274. </pre>
  275. <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
  276. sondage avec l'ID demandé n'existe pas.</p>
  277. <div class="section">
  278. <h2><a id="un-raccourci-get-object-or-404" name="un-raccourci-get-object-or-404">Un raccourci : get_object_or_404()</a></h2>
  279. <p>Il est vraiment très courant d'utiliser <tt class="docutils literal"><span class="pre">get_object()</span></tt> et de déclencher
  280. <tt class="docutils literal"><span class="pre">Http404</span></tt> si l'objet n'existe pas. Django fournit un raccourci. Voici la vue
  281. <tt class="docutils literal"><span class="pre">detail()</span></tt>, réécrite:</p>
  282. <pre class="literal-block">
  283. from django.shortcuts import render_to_response, get_object_or_404
  284. # ...
  285. def detail(request, poll_id):
  286. p = get_object_or_404(Poll, pk=poll_id)
  287. return render_to_response('polls/detail.html', {'poll': p})
  288. </pre>
  289. <p>La fonction <tt class="docutils literal"><span class="pre">get_object_or_404()</span></tt> prend un modèle Django en premier argument
  290. et un nombre arbitaire d'arguments mot-clés, qu'elle passe à la fonction
  291. <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>
  292. <div class="admonition-philosophie admonition">
  293. <p class="first admonition-title">Philosophie</p>
  294. <p>Pourquoi utilisons-nous une fonction utilitaire <tt class="docutils literal"><span class="pre">get_object_or_404()</span></tt> au
  295. lieu de récupérer automatiquement les exceptions <tt class="docutils literal"><span class="pre">DoesNotExist</span></tt> de haut
  296. niveau, ou avoir l'API du modèle qui déclenche <tt class="docutils literal"><span class="pre">Http404</span></tt> au lieu de
  297. <tt class="docutils literal"><span class="pre">DoesNotExist</span></tt> ?</p>
  298. <p class="last">Parce que ça serait coupler la couche du modèle avec la couche de la vue.
  299. Une des règles d'or de la conception de Django est de maintenir ce
  300. découplage entre les différentes couches.</p>
  301. </div>
  302. <p>Il y a également une fonction <tt class="docutils literal"><span class="pre">get_list_or_404()</span></tt>, qui fonctionne
  303. 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>
  304. 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>
  305. </div>
  306. </div>
  307. <div class="section">
  308. <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>
  309. <p>Lorsque vous levez une <tt class="docutils literal"><span class="pre">Http404</span></tt> à partir d'une vue, Django va charger une vue
  310. spéciale qui s'occupe des erreurs 404. Il la trouve en cherchant la variable
  311. <tt class="docutils literal"><span class="pre">handler404</span></tt>, qui est une chaîne de caractères utilisant la syntaxe Python à
  312. points -- le même format qui est utilisé par l'URLconf. Une vue 404 en elle-même
  313. n'a rien de particulier : c'est juste une vue classique.</p>
  314. <p>Vous n'avez normalement pas à vous soucier de l'écriture des vues 404.
  315. Par défaut les URLconfs ont la ligne suivante en en-tête :</p>
  316. <blockquote>
  317. from django.conf.urls.defaults import *</blockquote>
  318. <p>Cela permet de prendre en compte le paramètre <tt class="docutils literal"><span class="pre">handler404</span></tt> pour le module
  319. courrant. Comme vous pouvez le constater dans <tt class="docutils literal"><span class="pre">django/conf/urls/defaults.py</span></tt>,
  320. <tt class="docutils literal"><span class="pre">handler404</span></tt> correspond par défaut à
  321. <tt class="docutils literal"><span class="pre">'django.views.defaults.page_not_found'</span></tt>.</p>
  322. <p>Encore trois remarques au sujet des vues 404 :</p>
  323. <blockquote>
  324. <ul class="simple">
  325. <li>La vue 404 est aussi appelée si aucune des expressions rationnelle de
  326. l'URLconf ne correspond à l'adresse demandée.</li>
  327. <li>Si vous ne définissez pas votre propre vue 404 -- et utilisez celle par
  328. défaut, ce qui est recommandé -- vous devez quand même créer un template
  329. <tt class="docutils literal"><span class="pre">404.html</span></tt> à la racide de votre dossier de templates.</li>
  330. <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
  331. 404 utilisera ce template pour toutes les erreurs 404.</li>
  332. </ul>
  333. </blockquote>
  334. </div>
  335. <div class="section">
  336. <h1><a id="crire-une-vue-500-erreur-serveur" name="crire-une-vue-500-erreur-serveur">Écrire une vue 500 (erreur serveur)</a></h1>
  337. <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
  338. vue appelée en cas d'erreur du serveur. Les erreurs du serveur lorsque vous avez
  339. des erreurs d'exécution dans le code de vos vues.</p>
  340. </div>
  341. <div class="section">
  342. <h1><a id="utiliser-le-syst-me-de-template" name="utiliser-le-syst-me-de-template">Utiliser le système de template</a></h1>
  343. <p>Revenons à notre vue <tt class="docutils literal"><span class="pre">polls.detail</span></tt>. Considérant la variable de contexte
  344. <tt class="docutils literal"><span class="pre">poll</span></tt>, voici le template tel qu'il pourrait être:</p>
  345. <pre class="literal-block">
  346. &lt;h1&gt;{{ poll.question }}&lt;/h1&gt;
  347. &lt;ul&gt;
  348. {% for choice in poll.choice_set.all %}
  349. &lt;li&gt;{{ choice.choice }}&lt;/li&gt;
  350. {% endfor %}
  351. &lt;/ul&gt;
  352. </pre>
  353. <p>Le système de template utilise une syntaxe par points pour accéder aux attributs
  354. 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
  355. 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
  356. essaye avec les attributs de classe -- ce qui marche dans ce cas. Si ça n'avait
  357. 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
  358. poll.</p>
  359. <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> :
  360. <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>,
  361. ce qui renvoie un iterable d'objets « Choice » ce qui est parfait pour une
  362. utilisation dans un tag <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">for</span> <span class="pre">%}</span></tt>.</p>
  363. <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
  364. des templates.</p>
  365. </div>
  366. <div class="section">
  367. <h1><a id="simplifier-urlconfs" name="simplifier-urlconfs">Simplifier URLconfs</a></h1>
  368. <p>Prennons le temps de jouer un peu avec les vues et le système de templates. Lors
  369. de l'édition d'URLconf, vous avez dû vous rendre compte de la redondance
  370. présente dans le fichier:</p>
  371. <pre class="literal-block">
  372. urlpatterns = patterns('',
  373. (r'^polls/$', 'mysite.polls.views.index'),
  374. (r'^polls/(?P&lt;poll_id&gt;\d+)/$', 'mysite.polls.views.detail'),
  375. (r'^polls/(?P&lt;poll_id&gt;\d+)/results/$', 'mysite.polls.views.results'),
  376. (r'^polls/(?P&lt;poll_id&gt;\d+)/vote/$', 'mysite.polls.views.vote'),
  377. )
  378. </pre>
  379. <p>Le répertoire d'accès <tt class="docutils literal"><span class="pre">mysite.polls.views</span></tt> est dans chaque URL.</p>
  380. <p>Étant un cas courrant, le framework URLconf possède un raccourci pour les
  381. préfixes communs. Vous pouvez les factoriser et les placer en premier argument
  382. de <tt class="docutils literal"><span class="pre">patterns()</span></tt> de la façon suivante:</p>
  383. <pre class="literal-block">
  384. urlpatterns = patterns('mysite.polls.views',
  385. (r'^polls/$', 'index'),
  386. (r'^polls/(?P&lt;poll_id&gt;\d+)/$', 'detail'),
  387. (r'^polls/(?P&lt;poll_id&gt;\d+)/results/$', 'results'),
  388. (r'^polls/(?P&lt;poll_id&gt;\d+)/vote/$', 'vote'),
  389. )
  390. </pre>
  391. <p>C'est identique au précédent formatage. C'est juste un peu plus propre.</p>
  392. </div>
  393. <div class="section">
  394. <h1><a id="d-coupler-urlconfs" name="d-coupler-urlconfs">Découpler URLconfs</a></h1>
  395. <p>En parlant de ça, prennons le temps de découpler les URLs de notre appli de
  396. sondage à partir de la configuration de notre projet Django. Les applis Django
  397. sont censées être « pluggables » -- ce qui signifie que chaque application peut
  398. être transférée sur une autre installation de Django avec le minimum de
  399. désagréments.</p>
  400. <p>Notre appli de sondage est pas mal découplée pour le moment grâce à la structure
  401. 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
  402. paramètres de Django : l'URLconf.</p>
  403. <p>Nous avons édité les URLs dans <tt class="docutils literal"><span class="pre">mysite/urls.py</span></tt>, mais la conception des URLs
  404. d'une appli est spécifique à l'application, pas à l'installation de Django --
  405. déplaçons donc les URLs dans le dossier de notre appli.</p>
  406. <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,
  407. modifiez <tt class="docutils literal"><span class="pre">mysite/urls.py</span></tt> pour retirer les URLs spécifiques au sondage et
  408. insérez un <tt class="docutils literal"><span class="pre">include()</span></tt>:</p>
  409. <pre class="literal-block">
  410. (r'^polls/', include('mysite.polls.urls')),
  411. </pre>
  412. <p><tt class="docutils literal"><span class="pre">include()</span></tt>, permet simplement d'établir une référence à une autre URLconf.
  413. Notez l'absence de <tt class="docutils literal"><span class="pre">$</span></tt> (détection de fin de chaîne de caractère) dans
  414. l'expression rationnelle mais la présence d'un slash final. Lorsque Django
  415. rencontre un <tt class="docutils literal"><span class="pre">include()</span></tt>, il extrait tout ce qui suit l'URL détectée et
  416. l'envoie à l'URLconf inclus pour un traitement ultérieur.</p>
  417. <p>Voici ce qu'il se passe si un utilisateur se rend sur « /polls/34/ » avec ce
  418. système :</p>
  419. <ul class="simple">
  420. <li>Django va rencontrer <tt class="docutils literal"><span class="pre">'^polls/'</span></tt></li>
  421. <li>Il va enlever la partie reconnue (<tt class="docutils literal"><span class="pre">&quot;polls/&quot;</span></tt>) et envoyer le texte restant --
  422. <tt class="docutils literal"><span class="pre">&quot;34/&quot;</span></tt> -- à l'URLconf monsite.polls.urls' pour un traitement ultérieur.</li>
  423. </ul>
  424. <p>Maitenant que le découplage est effectué, il est nécessaire de découpler
  425. l'URLconf de 'monsite.polls.urls' en enlevant les préfixes « polls/ » à chaque
  426. ligne:</p>
  427. <pre class="literal-block">
  428. urlpatterns = patterns('monsite.polls.views',
  429. (r'^$', 'index'),
  430. (r'^(?P&lt;poll_id&gt;\d+)/$', 'detail'),
  431. (r'^(?P&lt;poll_id&gt;\d+)/results/$', 'results'),
  432. (r'^(?P&lt;poll_id&gt;\d+)/vote/$', 'vote'),
  433. )
  434. </pre>
  435. <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
  436. l'aspect plug-and-play des URLs. Maintenant que les sondages ont leur propre
  437. URLconf, ils peuvent être placés à la suite de « /polls », ou de « /fun_polls »,
  438. ou de « /content/polls », ou de n'importe quelle URL, et l'appli sera toujours
  439. fonctionnelle.</p>
  440. <p>Toute l'appli de sondage se base sur des URL relatives, non sur des URLs
  441. absolues.</p>
  442. <p>Lorsque vous avez assimilé l'écriture des vues, lisez la
  443. <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
  444. formulaires et les vues génériques.</p>
  445. <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
  446. documentation de Django</a>.</p>
  447. <p>Cette traduction correspond à la révision 3589 (post 0.95).</p>
  448. </div>