Tutos Django

Le langage de Templates - tag et filtres

Vous  aurez remarqué que django utilise un langage spécifique pour travailler avec les templates. La documentation officielle sur le langage de templates django peut être trouvée ici : The Django template language. Vous pouvez également trouver une version non officielle traduite en français ici (attention cependant, cela date d'aout 2006).

Premièrement, vous avez du remarquer que nous avons souvent utilisé les caractères {{ ... }} pour afficher une variable.
C'est en effet ces caractères qui vont nous permettre d'accéder à une variable, et mieux, si celle-ci est un objet, nous allons pouvoir accéder à ses attributs à l'aide du caractère point : "."

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

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

Si par mégarde, vous tentez d'accéder à une variable qui n'existe pas, celle-ci sera remplacée par une chaine vide spécifiée par défaut par la variable globale TEMPLATE_STRING_IF_INVALID.

La deuxième chose que nous avons énormément utilisé sont les boucles 'for' et les conditions 'if'. Vous avez pu remarquer que nous avions utilisé les balises {% ... %} pour travailler avec. Nous allons maintenant découvrir que nous pouvons les combiner avec des filtres et des tags :)

Il est utile de connaître comment commenter ses blocs de templates, pour cela il faudra utiliser les balises {# ... #}, exemple :

{# {% if foo %}bar{% else %} #}

Un tag qui vous sera fortement utile est 'autoescape', il permet de spécifier si le texte entre ce bloc doit être évalué comme 'échappé' ou non.

Par défaut en Django, chaque template échappe automatiquement ses variables reçues. Cela joue spécifiquement sur ces cinq caractères :
< est converti en &lt;
> est converti en &gt;
' (simple apostrophe) est convertie en &#39;
" (double apostrophe) est convertie en &quot;
& est converti en &amp;

C'est pourquoi si vous envoyez des chaînes de caractères depuis votre contrôleur contenant un de ces cinq caractères, vous devriez utiliser le tag autoescape. Exemple :

{% autoescape off %}
    {{ body }}
{% endautoescape %}

Deux valeurs sont disponibles : 'autoescape on' qui va en effet échapper le contenu (comportement par défaut) et 'autoescape off' qui va spécifier que nous devons afficher le contenu de la variable tel quel.

Le tag autoescape s'applique à tout un bloc. Si vous voulez uniquement spécifier à une variable qu'il n'est pas besoin de l'échapper, vous pouvez utiliser le filtre 'safe', le code précédent devient :

{{ body|safe }}

Simplement ! Pour utiliser un filtre, il suffit d'utiliser le caractère 'pipe' : | et spécifier le nom de celui-ci.
Au contraire, pour spécifier qu'il faut l'échapper (variable contenu dans un champs 'autoescape off'), il aurait fallu utilisé le filtre 'escape'.

'cycle' est un tag qui va vous permettre de réaliser différents comportement basés sur un cycle. Par exemple cela est utilisé pour alterner la couleur d'une ligne sur deux dans un tableau, exemple :

{% for o in some_list %}
    <tr class="{% cycle 'row1' 'row2' %}">
        ...
    </tr>
{% endfor %}

'row1' et 'row2' étant ici des classes css.
Une autre façon de faire aurait pu être d'utiliser des variables :

{% for o in some_list %}
    <tr class="{% cycle rowvalue1 rowvalue2 %}">
        ...
    </tr>
{% endfor %}

ou encore en mélangeant les deux méthodes :

{% for o in some_list %}
    <tr class="{% cycle 'row1' rowvalue2 'row3' %}">
        ...
    </tr>
{% endfor %}

La documentation officielle sur cycle est disponible ici : cycle

Le tag 'firstof' va vous permettre de récupérer le premier élément existant dans une énumération, exemple :

{% firstof var1 var2 var3 %}

est équivalent à :

{% if var1 %}
    {{ var1|safe }}
{% else %}{% if var2 %}
    {{ var2|safe }}
{% else %}{% if var3 %}
    {{ var3|safe }}
{% endif %}{% endif %}{% endif %}

plus d'infos sur le tag 'firstof' ici : firstof

Intéressons-nous à présent au tag for qui est sans doute la tag que vous allez utiliser le plus souvent dans vos templates.
Nous avons déjà vu le for ... in qui permet d'itérer sur une liste :

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

Nous aurions pu aussi itérer sur la liste en partant de la fin avec :

{% for obj in list reversed %}

Il est aussi possible d'itérer sur une liste de tuples, par exemple des coordonnées définies de cette façon : (x, y)

{% for x, y in points %}
    There is a point at {{ x }},{{ y }}
{% endfor %}

ou encore sur la paire clef:valeur d'un dictionnaire :

{% for key, value in data.items %}
    {{ key }}: {{ value }}
{% endfor %}

Ce qui va particulièrement nous intéresser sont les variables qu'il est possible d'utiliser au sein d'une boucle for :

Variables utilisables au sein d'une boucle for
VariableDescription.
forloop.counterla valeur de l'itération en cours (indexée à partir de 1)
forloop.counter0la valeur de l'itération en cours (indexée à partir de 0).
forloop.revcounterle nombre d'itérations qu'il reste à effectuer au sein de la boucle (indexé à partir de 1).
forloop.revcounter0le nombre d'itérations qu'il reste à effectuer au sein de la boucle (indexé à partir de 0).
forloop.firstVrai si c'est la première fois qu'on effectue un tour de boucle.
forloop.fastVrai si c'est la dernière fois qu'on effectue un tour de boucle.
forloop.parentloopPour les boucles encapsulées, cela fait référence à la boucle "précédent" l'actuelle.

Et nous n'oublions pas de citer un cas bien pratique : for ... empty qui nous permet de réaliser une action au cas où on ne rentre jamais dans la boucle :

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% empty %}
    <li>Sorry, no athlete in this list!</li>
{% endfor %}
<ul>

Le tag if est également très intéressant à étudier de part sa particularité. En effet, plusieurs tags sont disponibles pour effectuer différents types de conditions bien spécifiques à notre besoin.
Une utilisation basique de ce tag reviendrait à écrire :

{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% else %}
    No athletes.
{% endif %}

Voyons à présent ce que nous pouvons réaliser au niveau des conditions booléennes. On en connait trois principales : or, and et not que l'on peut utiliser ensemble.

{% if athlete_list and coach_list %}
    Both athletes and coaches are available.
{% endif %}

{% if not athlete_list %}
    There are no athletes.
{% endif %}

{% if athlete_list or coach_list %}
    There are some athletes or some coaches.
{% endif %}

{% if not athlete_list or coach_list %}
    There are no athletes or there are some coaches (OK, so
    writing English translations of boolean logic sounds
    stupid; it's not our fault).
{% endif %}

{% if athlete_list and not coach_list %}
    There are some athletes and absolutely no coaches.
{% endif %}

On retiendra que and est prioritaire sur or et donc cette ligne :

{% if athlete_list and coach_list or cheerleader_list %}

sera interprété comme :

if (athlete_list and coach_list) or cheerleader_list

Passons maintenant aux opérateurs de comparaison. On dénombre ==, !=, <, >, <=, >= ainsi que le mot clef in. Il est inutile de décrire ces opérateurs bien connus, mais intéressons-nous à in :

{% if "bc" in "abcdef" %}
  This appears since "bc" is a substring of "abcdef"
{% endif %}

{% if "hello" in greetings %}
  If greetings is a list or set, one element of which is the string
  "hello", this will appear.
{% endif %}

{% if user in users %}
  If users is a QuerySet, this will appear if user is an
  instance that belongs to the QuerySet.
{% endif %}

Le mot clef in permet donc de savoir si une chaîne de caractère ou un objet par exemple est présent dans une autre chaîne de caractère, une liste, un dictionnaire ou autre.

Au niveau des priorités, les opérateurs de comparaisons sont devant, viennent ensuite dans l'ordre : in not and or

ifchanged, ifequal et ifnotequal sont trois tags que l'on oublie parfois mais qui peuvent vous sauver de nombreuses heures de debug.

ifchanged va vérifier si une variable a changé depuis la dernière itération d'une boucle, ce tag ne fonctionne donc qu'à l'intérieur d'une boucle ! :

{% for match in matches %}
    <div style="background-color:
        {% ifchanged match.ballot_id %}
            {% cycle "red" "blue" %}
        {% else %}
            grey
        {% endifchanged %}
    ">{{ match }}</div>
{% endfor %}

Dans l'exemple ci-dessus, on vérifie si l'identifiant ballot de l'objet match a changé depuis la dernière itération de boucle, auquel cas on réalise un cycle qui alterne deux couleurs, sinon on utilise une couleur par défaut.

ifequal va être très intéressant quand vous ne pourrez pas comparer certaines variables avec l'opérateur == :

{% ifequal user.id comment.user_id %}
    ...
{% endifequal %}

Ce tag ne permet que de faire des comparaisons avec des chaînes de caractères ou les objets que reçoit le template (c'est à dire fournit par notre contrôleur).
ifnotequal fonctionne de la même façon qu'ifequal à la différence qu'il teste si les objets passés en argument ne sont pas égaux.

Il reste encore beaucoup d'autres tags à voir, mais nous nous attarderons encore sur trois tags importants : spaceless, url et with

spaceless, nous l'avons déjà vu, permet de retirer les espaces présents dans le bloc que nous englobons sans pour autant enlever les espaces présents à l'intérieur des tags html. Ce qui permet de générer un code propre et optimisé et ainsi développer avec un confort de visibilité.

{% spaceless %}
    <p>
        <a href="foo/">Foo Bar</a>
    </p>
{% endspaceless %}

retournera

<p><a href="foo/">Foo Bar</a></p>

Le tag url est très intéressant car il va nous permettre de récupérer au sein de notre template une url que nous avons déjà défini dans le fichier urls.py de notre projet.

{% url path.to.some_view v1 v2 %}

Le premier argument est le chemin vers une fonction définie dans notre contrôleur (views.py) et les autres sont les arguments que peut prendre en compte notre url qui sont bien sûr optionnels.
Cependant au lieu de spécifier le chemin vers la fonction du contrôleur, il est possible d'utiliser le nom de l'url que nous désirons récupérer.
Souvenez-vous dans notre cas avec l'application 'myform', nous avions défini urlpatterns de la sorte :

urlpatterns = patterns('mysite.myform.views',
                       url(r'^contact$', 'contact', name='contact'),
)

Nous pouvons alors utiliser le tag url en lui spécifiant le nom de l'url déclarée avec l'attribut "name" qui vaut ici 'contact', ce qui donnera :

{% url contact %}

et produira l'url : /contact
Je vous conseille d'ailleurs d'utiliser toujours cette façon de faire car elle permet de s'y retrouver bien plus facilement et apporte une meilleure maintenance du code.

with est un tag vraiment appréciable puisqu'il va vous permettre de mettre en cache une variable, afin de l'utiliser tout au long du bloc de code. Ce qui permet de faire moins d'appels à la base de données par exemple et de renommer une variable avec un nom plus court par la même occasion.

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

Notez que la variable déclarée avec le tag with n'est disponible que dans le bloc with.

Nous avons passé en revue une bonne partie des tags de django, surtout les plus utiles, mais il en reste beaucoup d'autres que vous pourrez trouver sur la documentation officielle : Built-in tag reference

Nous allons maintenant lister quelques filtres les plus utilisés sans pour autant les décrire car il y en a énormément.
Les plus intéressants étant :

addslashes, capfirst, cut, date, default, default_if_none, dictsort, escape, escapejs, first, fix_ampersands, last, length, length_is, linebreaks, lower, make_list, pluralize, remove_tags, safe, slice, striptags, upper, urlencode, urlize, yesno

Nous en avons déjà vu certains mais vous pouvez retrouver toute la liste des filtres avec des exemples de compréhension sur la documentation officielle : Built-in filter reference

Enfin, comme il est difficile de retenir tout ça, un projet nommé django cheat sheet a vu le jour et permet de rassembler sur deux pages d'un document, tout ce qu'il y a de plus intéressant sur les tags et les filtres : django cheat sheet

Je vous invite vivement à regarder de plus près ce projet qui permet d'avoir une belle feuille de route concernant les tags et filtres :)
Mais ce n'est pas tout car il inclut également les modèles et les formulaires, chose que nous avons déjà vu ensemble :)

Article suivant

Article précédent

Articles associés

Articles similaires

Commentaires

Les commentaires sont fermés.

Pingbacks

Les pingbacks sont fermés.