Le langage de template Django : Pour les auteurs de templates

vignette

Le langage de template Django a été conçu dans l'idée d'être un bon compromis entre puissance et facilité. Il est facilement accessible aux personnes ayant l'habitude de travailler avec du HTML. Si vous avez déjà utilisé un autre langage de template, comme Smarty ou CheetahTemplate, vous n'aurez aucune difficulté à adopter les templates Django.

Templates

Un template est un simple fichier texte. Il peut générer n'importe quel type de fichier texte (HTML, XML, CSV, etc).

Un template contient des variables qui seront remplacées par leurs valeurs lors de son évaluation et des tags qui controlent la logique du template.

Ci-dessous un template minimal qui illustre les bases. Chaque élément sera expliqué plus tard dans ce document.:

{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}

<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>

<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}

Philosophie

Pourquoi utiliser un template au format texte et non au format XML (comme celui du TAL Zope) ? Nous voulions que le langage de template puisse être utilisé pour plus que des templates XML/HTML. À World Online, nous l'utilisons pour les mails, la JavaScript et le CSV. Vous pouvez utiliser le langage de template pour tout format basé sur du texte.

Oh, encore un truc : Rendre du XML éditable par les humains est sadique !

Variables

Les variables ressemblent à {{ variable }}. Lorsque le moteur de template rencontre une variable, il évalue cette variable et la remplace par son résultat.

Utilisez un point (.) pour accéder aux attributs d'une variable.

En coulisses

Techniquement, lorsque le système de template rencontre un point, il effectue les recherches suivantes, dans cet ordre :

  • Dictionaire
  • Attribut
  • Appel de méthode
  • Index de liste

Dans le précédent exemple, {{ section.title }} sera remplacé par l'attribut title de l'objet section.

Si vous utilisez une variable qui n'existe pas, le système de template va insérer la valeur contenue dans le paramètre TEMPLATE_STRING_IF_INVALID qui correspond par défaut à '' (chaîne vide).

Lisez Utiliser les références incluses, ci-dessous, pour vous aider à connaître les variables disponibles pour un template donné.

Filtres

Vous pouvez modifier des variables lors de l'affichage en utilisant des filtres.

Les filtres ressemblent à {{ name|lower }}. Ceci affiche la valeur de la variable {{ name }} après avoir été filtrée par le filtre lower, qui convertit un texte en minuscule. Utilisez un pipe (|) pour appliquer un filtre.

Les filtres peuvent « s'enchaîner ». La sortie d'un filtre est l'entrée du suivant. {{ text|escape|linebreaks }} est souvent utilisé pour échapper le contenu d'un texte et convertir ensuite les sauts de lignes en tags <p>.

Certains filtres possèdent des arguments. Un argument de filtre ressemble à : {{ bio|truncatewords:"30" }}. Cela va afficher les 30 premiers mots de la variable bio. Les arguments de filtres sont toujours entre double quotes.

La Référence des filtres inclus ci-dessous décrit l'ensemble des ces filtres.

Tags

Les tags ressemblent à : {% tag %}. Les tags sont plus compliqués que les variables : certains génèrent une sortie de texte, d'autres contrôlent le flux grâce aux boucles ou à la logique, et certains chargent des informations externes dans le template pouvant être utilisées par la suite.

Certains tags requièrent des tags de début et de fin (càd. {% tag %} ... contenu du tag ... {% endtag %}). La Référence des tags inclus ci-dessous décris l'ensemble de ces tags. Vous pouvez écrire vos propres tags si vous connaissez le Python.

Héritage des templates

La plus intéressante -- mais aussi la plus complexe -- partie du moteur de template de Django est l'héritage. L'héritage des templates vous permet de construire un template « squelette » de base contenant tous les éléments usuels de votre site et définissant des blocs que les templates enfants pourront écraser et/ou compléter.

Il est plus simple, pour comprendre l'héritage des templates, de commencer par un exemple:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <link rel="stylesheet" href="style.css" />

&lt;title&gt;{% block title %}Mon super site{% endblock %}&lt;/title&gt;

</head>

<body> <div id="sidebar"> {% block sidebar %} <ul>

        &lt;li&gt;&lt;a href=&quot;/&quot;&gt;Accueil&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;/blog/&quot;&gt;Blog&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    {% endblock %}
&lt;/div&gt;

&lt;div id=&quot;content&quot;&gt;
    {% block content %}{% endblock %}
&lt;/div&gt;

</body>

Ce template, que nous appelerons base.html, définit un simple squelette HTML que vous pouvez utiliser pour une page à deux colonnes. C'est le boulot des templates « enfants » de compléter les blocs vides avec du contenu.

Dans cet exemple, le tag {% block %} définit trois blocs que les templates enfants peuvent compléter. Tout ce que les tags block font c'est d'indiquer au moteur de template qu'un template enfant peut écraser ces parties du template.

Un template enfant pourrait ressembler à ça:

{% extends "base.html" %}

{% block title %}Mon super blog{% endblock %}

{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>

    <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

Le tag {% extends %} est la clé ici. Il indique au moteur de template que ce template « étend » un autre template. Lorsque le système de template évalue ce template, il commence par localiser le parent -- dans notre cas, « base.html ».

À ce moment, le moteur de template va tenir compte des trois tags {% block %} dans base.html et remplacer ces blocs avec le contenu du template enfant. En fonction de la valeur de blog_entries, la sortie devrait être proche de:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <link rel="stylesheet" href="style.css" />

    <title>Mon super blog</title>
</head>

<body>
    <div id="sidebar">
        <ul>

            <li><a href="/">Accueil</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>

    </div>

    <div id="content">
        <h2>Billet un</h2>
        <p>C'est mon premier billet.</p>

        <h2>Billet deux</h2>
        <p>C'est mon second billet.</p>
    </div>
</body>

Notez que tant que le template enfant ne redéfinit pas le bloc sidebar, la valeur du template parent est utilisée à la place. Le contenu au sein d'un tag {% block %} dans un template parent est toujours utilisé en dernier lieu.

Vous pouvez utiliser autant de niveaux d'héritage que désiré. L'une des manières habituelle d'utiliser l'héritage est l'approche à trois niveaux suivante :

  • Créez un template base.html qui définit l'apparence globale de votre site.
  • Créez un template base_NOMDESECTION.html pour chaque section de votre site. Par exemple, base_news.html, base_sports.html. Ces templates étendent tous base.html et incluent le style/design spécifique à la section.
  • Créez un template individuel pour chaque type de page, comme les articles de nouveautés ou les billets d'un blog. Ces templates étendent le template de la section appropriée.

Cette approche maximise la réutilisation du code et rend facile l'ajout de blocs partagés entre plusieurs parties du site comme la navigation.

Voici quelques astuces pour utiliser l'héritage :

  • Si vous utilisez {% extends %} dans un template, ça doit être le premier tag du template. Dans le cas contraire l'héritage ne fonctionnera pas.
  • Il vaut mieux avoir de nombreux tags {% block %} dans vos templates de base. Rappelez-vous, les templates enfants n'ont pas à redéfinir la totalité des blocs, vous pouvez donc remplir les blocs avec un contenu intéressant par défaut. Ne redéfinissez ensuite que ceux dont vous avez besoin. Il vaut mieux en avoir plus que pas assez.
  • Si vous vous apercevez d'une duplication du contenu dans de nombreux templates, cela signifie probablement que vous devriez déplacer ce contenu dans un {% block %} au sein d'un template parent.
  • Si vous avez besoin du contenu issu du template parent, la variable {{ block.super }} est là pour ça. C'est intéressant si vous souhaitez ajouter quelquechose au contenu parent existant au lieu de l'écraser.

Pour finir, notez l'impossibilité de définir plusieurs tags {% block %} ayant le même nom dans le même template. Cette limitation existe car un tag block fonctionne dans les deux directions. Cela signifie qu'un tag block ne procure pas seulement un espace à compléter -- il définit aussi au niveau enfant le contenu parent accessible dans cet espace (par block.super).

Utiliser les références incluses

L'interface d'administration de Django inclue une référence complète à l'ensemble des tags et filtres de template disponibles pour un site donné. Pour y accéder, rendez vous dans votre interface d'administration et cliquez sur le lien « Documentation » en haut à droite de la page.

La référence est divisée en 4 sections : tags, filtres, modèles et vues.

Les sections tags et filtres décrivent tous les tags de base (en fait, les références de tag et de filtre qui suivent proviennent directement de ces pages) ainsi que vos propres bibliothèques de tags et de filtres disponibles.

La page des vues est la plus intéressante. Chaque URL de votre site a une entrée distincte ici, et cliquer sur cette URL vous donnera accès :

  • Au nom de la fonction qui génère cette vue.
  • À une description succinte de ce que fait la vue.
  • Au contexte, ou une liste de variables accessibles dans le template de la vue.
  • Au nom du ou des template(s) qui est(sont) utilisé(s) pour cette vue.

Chaque page de documentation d'une vue dispose aussi d'un bookmarklet que vous pouvez utiliser pour aller directement de n'importe quelle page à la page de documentation de cette vue.

Les sites propulsés par Django utilisant généralement des objets de base de données, la section modèles de la page de documentation décrit chaque type d'objet dans le système courant avec l'ensemble des champs disponibles dans cet objet.

L'ensemble des pages de documentation vous renseigne sur chaque tag, filtre, variable et objet disponible pour un template donné.

Tags personnalisés et bilbiothèques de filtres

Certaines applications procurent des tags personnalisés et des bilbiothèques de filtres. Pour y accéder dans un template, utilisez le tag {% load %}:

{% load comments %}

{% comment_form for blogs.entries entry.id with is_public yes %}

Ci-dessus, le tag load charge la bibliothèque de tags comments, ce qui rend ensuite le tag comment_form utilisable. Consultez la rubrique documentation de votre interface d'administration pour trouver la liste des bibliothèques personnalisées de votre installation.

Le tag {% load %} peut prendre plusieurs noms de bibliothèques à la fois, séparés par des espaces. Exemple:

{% load comments i18n %}

Bibliothèques personnalisées et héritage des templates

Lorsque vous chargez un tag personnalisé ou une bibliothèque de filtres, les tags/filtres ne sont accessibles qu'au sein du template courant -- et aucun des templates parents ou enfants issus de l'héritage des templates n'y a accès.

Par exemple, si un template foo.html a {% load comments %}, un template enfant (par exemple, un qui a {% extends "foo.html" %}) n'aura pas accès aux filtres et tags du template comments. Le template enfant doit avoir son propre {% load comments %}.

C'est une fonctionnalité pour la maintenabilité et l'intégrité des templates.

Référence des tags et filtres inclus

Pour ceux ne disposant pas d'une interface d'administration, la référence des tags et filtres suit. En raison de la personnalisation possible de Django, la référence dans votre administration prévaut sur celle-ci concernant l'accessibilité et la fonction des tags et filtres.

Référence des filtres inclus

La suite de la traduction est en cours, j'ai jugé qu'il était plus important de publier cette première partie qui pose les bases en attendant. Il faut avouer que la suite (en) est moins passionnante...

Vous pouvez maintenant retourner à la page d'accueil des traductions de la documentation de Django.

Cette traduction correspond à la révision 3589 (post 0.95).

— 15/08/2006

Articles peut-être en rapport

Commentaires

Bernard le 16/08/2006 :

waaaoou merci beaucoup! J'en suis a mes premiers babultiements en Python et je voulais justement utiliser django pour un projet web personnel!

djangofan le 13/11/2006 :

djangofan le 13/11/2006 :

Une petite question à propos des templates. J'ai une classe Annonce à laquelle se rattache une classe Photo. Je voudrais afficher une photo dans ma page web, mais je n'arrive pas à extraire l'url du lien.

J'ai essayé :

<img src="{{ annonce.photo[1].url }}" width="120" height="90" />
<img src="{{ annonce.photo(1).url }}" width="120" height="90" />

mais ça fonctionne pas. Une idée de la syntaxe à utiliser ?

Merci

David, biologeek le 13/11/2006 :

Normalement, tu dois avoir créé une méthode get_aboslute_url() dans ton model qui te permet de récupérer cette url, cf la doc :

www.djangoproject.com/doc...

ps : et pour le djangobook c'est en cours de réflexion ;-).

djangofan le 13/11/2006 :

En fait c'est pas ça, d'ailleurs quand je me relis, c'est pas clair. :-D
Ce que je voudrais en faite c'est acceder à la valeur de la propriété url de la classe photo. Elle meme est une "sous-classe" de la classe annonce.

Je sais pas si je suis bien compréhensible !

David, biologeek le 13/11/2006 :

Pas vraiment :D
Il y a un moyen que tu me colles ton model quelquepart (ou par mail ?)

DjangoJO le 21/12/2006 :

Bonjour,

Voilà une petite question qui se pose !
J'ai un projet principale qui comporte une partie blog et une partie sondage et accueil. Comment faire pour appeler mon template accueil en y incorporant mon blog et mon sondage?

personnellement j'y arrive en appellant sondage herité de accueil OU blog herité de accueil mais je n'arrive pas à avoir les deux dans mon template accueil.

Merci

David, biologeek le 21/12/2006 :

Il y a trois solutions :

* soit tu passes par les vues génériques et dans ce cas il faut lire l'article de James www.b-list.org/weblog/200...

* soit tu mets tout ce dont tu as besoin dans le dictionnaire permettant que tu passes à ta vue.

* soit tu utilises les templatetags, une explication sur b-list aussi (site de référence) : www.b-list.org/weblog/200....

Tu peux m'envoyer ton code si tu veux plus d'explications.

djangofan2 le 21/02/2007 :

J'ai un champs :
CV = models.FileField("CV ", upload_to="candidats/", blank=True)

Et dans mon template je fait :

<input type="file" size=55 maxlength=100000 name="CV" id="id_CV">

Puis je vérifie dans ma partie administration et dans le champs CV il met que le nom du fichier donc il ne me telecharge pas dans le dossier"candidats" le CV!!!
(( ce qui marche bien sur si je rajoute une candidature à la main dans la partie administration.

Quelqu'un pourrai m'aider SVP.

Merci


David, biologeek le 21/02/2007 :

@djangofan2 : tu peux essayer de mettre un chemin absolu pour l'upload. Ah et n'oublie pas les " pour les valeurs de tes attributs dans ton html (pour size et maxlength).

DjangoFan2 le 26/02/2007 :

Bonjour,

J'aimerai tout simplement savoir si il est possible d'utiliser le search_field de la partie admin de django dans un template personnel ?

A part si bien sûr, il existe un module de recherche de django ? ou bien alors il faut le faire soit même ?

Comme on peut le voir sur la plus part des sites internet il y a toujours une zone recherche ...

Merci

David, biologeek le 26/02/2007 :

@DjangoFan2 : c'est une vue à coder soit-même car elle est très spécifique de l'application développée.

DjangoFan2 le 26/02/2007 :

Merci,
Bien je vais m'y mettre sans trop tarder alors !!!

Et juste pour savoir ::
- j'ai un menu en javascript qui fonctionne très bien mais quand j'utilise les fichiers js de django genre calendar.js il ne se passe rien serais-tu pourquoi ?

- L'utilisation d'ajax est-il possible ? si oui comment faire pour inclure un fichier (exemple en php :<? include("menu.php");?>

Merci beaucoup pour tous ses renseignements !!!


David, biologeek le 26/02/2007 :

> j'ai un menu en javascript qui fonctionne très bien mais quand j'utilise les fichiers js de django genre calendar.js il ne se passe rien serais-tu pourquoi ?

Il doit y avoir un conflit entre les variables js de tes deux fichiers (?)

> L'utilisation d'ajax est-il possible ?

Bien sûr !

> si oui comment faire pour inclure un fichier (exemple en php :<? include("menu.php");?>

Ça c'est de l'héritage de template, pas de l'AJAX. cf le billet de Jeff Croft : www2.jeffcroft.com/blog/2...

djangoNew le 28/02/2007 :

Merci beaucoup pour le tuto, c'est très clair et bien expliqué .

Par contre j'aimerai savoir si c'est possible de comparer une variable dans les "if" ( exemple : {% if cpt=2 %} ou faire le même style d'opération comme en php.

Car j'ai créer un menu en html et javascript, mais j'ai besoin que ce menu soit complétement dynamique donc il faut que je le remplisse via un modéle.

Merci beaucoup

Et encore bravo pour le site

David, biologeek le 28/02/2007 :

Il existe ifequal pour ça : {% ifequal cpt 2 %}

Mais pour ton cas, un block extraclass dans chacune des classes de ton menu devrait être plus adapté, enfin c'est ainsi que je procède...

Bienvenue dans l'univers Django :-)

djangoNew le 02/03/2007 :

Me revoilà pour d'autre petites questions sur des choses que je n'ai pas trop trop compris !
Merci encore pour toutes ses explications !

C'est une question d'heritage ! En ayant deux module différents genre contact et FAQ comment puis je heriter leurs templates respectif sur un même template general genre base.html !!!

J'ai compris l'histoire des templates car c'est très bien expliqué mais là je suis un peu perdu !

MERCI d'avance

David, biologeek le 03/03/2007 :

Il suffit de faire un {% extends "base.html" %} en première ligne de ton template. Si tu veux tu peux regarder ce que ça donne pour le site de django-fr.org : trac.django-fr.org/trac/b...

djangoNew le 05/03/2007 :

Merci pour le lien, j'ai regardé les différents templates mais le probléme qui se pour moi, ne se pose pas pour les templates du lien en question, car le texte est rentré en dur dans la page, que personellement je recupére le texte d'une view.

Je me suis peut être mal exprimé la derniére fois !

La seule action qui déclenche une view c'est l'url en question (a ce que j'ai compris).
Si je veux afficher les articles de mon module et les contacts de mon autre module normalement il faut que j'appele la view "Articles" et la view "Contact" avec leurs url respectif ( genre : www.monsite/article et www.monsite/contact) !
Mais moi je voudrai que quand je tape par exemple l'url : www.monsite.com/accueil je puisse avoir les articles et les contacts en bas de la page base.html.

Mais le problème qui se pose : Si j'appele www.monsite/Article, il vas me retourner la view correspondante avec la page article.html que j'"extends" de base.html mais comment faire pour que je puisse aussi appelé la view de contact et l'extends de base.html ??

Désolé mais je ne n'arrive vraiment pas à voir comment je puisse faire et à cause de se probléme, je ne peux avancer sur mon projet personel ...



David, biologeek le 05/03/2007 :

Les solutions possibles dans ce cas sont répertoriées dans un précédent commentaire : le numéro 8 (un peu plus haut), notamment les templatetags qui sont je pense la solution la plus élégante.

Ouarnier le 19/01/2010 :

Bonjour,

J'ai un projet qui a deux applications.
dans chacune de ces applications, j'ai une template defini. Une template qui affiche un budget de fonctionnement et dans l'autre appli, une template qui affiche un budget de personnel.

je voudrais faire une page tableau de bord qui affiche les deux templates ?
comment faire ?

j'ai lu le commentaire 8 mais je ne comprends pas comment faire ?
je n'arrive pas à comprendre comment je peux faire ça avec les templates tags.