title:      Vues génériques, héritage et templatetags : développez rapidement avec Django
slug:       vues-generiques-heritage-et-templatetags-developpez-rapidement-avec-django
date:       2007-04-24 08:48:42
type:       post
vignette:   images/logos/biologeek.png
contextual_title1:  Biologeek (enfin) propulsé par Django
contextual_url1:    20080423-biologeek-enfin-propulse-par-django
contextual_title2:  Ajout des flux RSS, du sitemap et des commentaires avec Django
contextual_url2:    20070623-ajout-des-flux-rss-du-sitemap-et-des-commentaires-avec-django
contextual_title3:  De Dotclear à Django : migration des données et redirections
contextual_url3:    20070523-de-dotclear-a-django-migration-des-donnees-et-redirections

<p>Suite de la <a href="https://larlet.fr/david/biologeek/archives/20070224-objectifs-et-motivations-de-la-refonte-de-ce-blog/">saga consacrée à la refonte de ce site</a>. Aujourd'hui, on s'attaque à la partie visible de l'iceberg avec des petits raccourcis de Django qui changent la vie™.</p>

<h2>URL et vues génériques</h2>


<p>Les vues génériques sont issues d'un constat simple&nbsp;: <strong>beaucoup de sites sont destinés à afficher des informations au sujet d'une ressource ou à afficher une liste de ressources</strong>. C'est justement le cas des billets d'un blog donc on ne va pas s'en priver&nbsp;! Par exemple si je considère ma <strong>ressource Post</strong>, je peux définir ma vue ainsi&nbsp;:</p>


<pre>urlpatterns = patterns('django.views.generic.list_detail',
    (r'^([-\w]+,)*[-\w]+/(?P&lt;slug&gt;[-\w]+)/$',
        'object_detail',
        dict(
            queryset = Post.published.all(),
            template_object_name = 'post',
            slug_field='slug'
        )
    ),
)</pre>


<p>L'expression régulière récupère ce qui est en <strong>/tag1,tag2/titre-du-billet/</strong> et appelle la vue générique <strong>object_detail</strong> pour afficher le <strong>Post</strong> qui va matcher avec le slug (qui est le titre du billet sous forme d'<abbr title="Uniform Resource Locator">URL</abbr>). C'est tout simple et je n'ai plus qu'à me soucier du template associé pour afficher les informations souhaitées.</p>


<p>Dans le cas d'une <strong>agrégation de ressources</strong> (comme pour le journal par exemple), la définition ressemble à&nbsp;:</p>



<pre>urlpatterns = patterns('django.views.generic.list_detail',
    (r'^journal/$',
        'object_list',
        dict(
            queryset = Post.published.all()[:10],
            template_object_name = 'post'
        )
    ),
)</pre>


<p>Ici on appelle <strong>object_list</strong> pour afficher à l'URL <strong>/journal/</strong> la liste des derniers billets publiés. Je préfère spécifier à chaque fois le <em>template_object_name</em> car j'aime bien savoir ce que je manipule dans les templates (par défaut le nom de la variable est <em>object</em>).</p>


<p>Comme vous pouvez le voir <a href="http://biologeek.googlecode.com/svn/trunk/urls.py">dans le fichier complet</a>, <strong>un blog est défini en quelques lignes de code seulement</strong>... c'est toute la puissance de Django.</p>


<h2>Héritage des templates</h2>


<p>Une autre fonctionnalité qui permet de gagner énormément de temps. <strong>L'héritage des templates de Django est assez pythonique si l'on se représente les fichiers comme des classes et les blocs comme des fonctions</strong>. Chaque template peut hériter d'un template parent et peut surclasser les blocs existants dans ce template en définissant des blocs du même nom (il est aussi possible d'utiliser le contenu des blocs parents en plus du contenu propre au bloc du template courant avec <strong><q> block.super </q></strong>). J'ai du mal à expliquer clairement ce fonctionnement donc le mieux c'est peut-être d'aller lire <a href="http://www2.jeffcroft.com/blog/2006/feb/25/django-templates-the-power-of-inheritance/">le billet de Jeff Croft</a> à ce sujet qui contient des exemples.</p>


<p>Au début on ne se rend pas vraiment compte de la puissance d'un tel système mais à l'utilisation c'est vraiment du <abbr title="Don&#039;t Repeat Yourself">DRY</abbr> à l'état pur.</p>


<h2>Ces petits bouts de code...</h2>


<p>... qui permettent de gagner du temps. Ils ont appelé ça <strong>templatetags</strong> dans django. Les fonctions définies de la sorte peuvent être facilement appelées dans un template pour afficher des informations particulières, c'est généralement utilisé lorsque vous devez avoir accès à des informations similaires à plusieurs endroits du site et que vous ne voulez pas avoir à récupérer cette information dans chaque vue. Un bon exemple vaut mieux qu'un long discours, je veux par exemple afficher les 5 derniers billets publiés dans le pied de page du site. Seules deux lignes sont nécessaires au niveau de mon template&nbsp;:</p>


<pre>{% get_latest_objects journal.Post 5 as latest_posts %}
{% display_footer_posts %}</pre>


<p>Le premier appel récupère les 5 objets de type Post et les place dans la variable <em>latest_post</em>. Le second est un <em>inclusion tag</em> qui à partir de cette variable et d'un bout de template va générer la liste attendue (en html). Certains des templates sont génériques et <a href="http://code.google.com/p/django-template-utils/">partagés</a> donc c'est autant de code à produire en moins. À ce sujet, <a href="http://www.djangosnippets.org/">DjangoSnippets</a> est une excellente ressource aussi.</p>


<p><strong>J'espère que ces quelques exemples vous auront convaincu de la rapidité de développement avec Django</strong> (même si je sais bien que la refonte traîne un peu... ce qui n'est pas vraiment la meilleure publicité que l'on puisse faire ;-)).</p>


<p>Prochaine étape&nbsp;: ma bête noire, <a href="https://larlet.fr/david/biologeek/archives/20070523-de-dotclear-a-django-migration-des-donnees-et-redirections/">la migration des données</a>. C'est dommage car <a href="http://www.aswmc.com/dbmigration/">des solutions sont en train d'être mises en place</a> afin de faciliter ce genre d'opérations mais bon j'ai déjà assez attendu comme ça, je pense que je vais le faire à la main (d'ailleurs si vous avez des conseils/outils). À signaler également la sortie de <a href="http://code.google.com/p/django-openid/">Django OpenID</a> développé par <a href="http://simonwillison.net/2007/Apr/24/openidconsumer/">Simon Willison</a> (M. OpenID mais aussi à l'origine de Django), je suivais l'évolution du projet et je comptais justement lui demander s'il avait une date de prévue pour la sortie, c'est maintenant chose faite, ça va pas mal me simplifier la tâche.</p>
