Templates Django : tags et filtres personnalisés

Dango est fourni avec les piles : de nombreux outils sont disponibles dans la distribution de base, ceci incluant des filtres et tags de templates. Quand cela ne suffit pas, vous pouvez définir vos propres tags et filtres de template pour vos besoins personnels. Cette page vous apprendra à le faire.

Rappels sur les tags et filtres de templates

Dans nos vues (templates) Django, nous utilisons généralement des variables positionnées dans le contexte via les contrôleurs (views) ou des context processors. Pour manipuler ces variables et les présenter au mieux, nous disposons de deux types d'outils :

  • Les filtres, qui permettent de modifier le rendu des variables. Exemple : {{ une_chaine|lower }} permet de convertir la chaîne une_chaine en minuscules pour affichage.
  • Les tags, qui permettent des manipulations plus complexes des variables, par exemple des itérations (boucles), l'extension de templates, etc. Exemple d'utilisation d'un tag :
    {% for objet in liste_objets %}
        {{ objet.name }}
    {% endfor %}

Création de filtres et tags perso

Dans certaines situations, il est commode de pouvoir définir ses propres filtres et tags. Ceci est rendu possible très simplement par Django. Les filtres et tags custom sont définis au niveau de chaque application. Nous allons pour cela :

  • Créer un répertoire templatetags dans le répertoire de l'application.
  • Créer dans ce répertoire un fichier Python destiné à contenir nos tags.
  • Implémenter dans ce fichier autant de fonctions que nécessaire, une fonction correspondant à un tag.

Les fonctions définissant des tags peuvent disposer du contexte du template depuis lequel ils sont appelés, ainsi que de paramètres éventuellement passés via l'appel du tag ou filtre dans le template.

Pas clair ? Imaginons que vous souhaitiez insérer sur vos pages des offres de produits issues du site Amazon (comme vous pouvez en voir sur certaines pages de ce site de formation à Django). Pour faire ceci, Amazon met à votre disposition des portions de code à insérer directement sur votre site, et qui ressemblent à ceci :

<a href="http://www.amazon.fr/gp/product/2212134150/ref=as_li_ss_il?ie=UTF8&camp=1642&creative=19458&creativeASIN=2212134150&linkCode=as2&tag=imaensom-21"><img border="0" src="http://ws-eu.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=2212134150&Format=_SL160_&ID=AsinImage&MarketPlace=FR&ServiceVersion=20070822&WS=1&tag=imaensom-21" ></a><img src="http://ir-fr.amazon-adsystem.com/e/ir?t=imaensom-21&l=as2&o=8&a=2212134150" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

Pas très folichon, n'est-ce pas ? Plutôt que d'insérer manuellement à chaque fois, et étant donné que les produits Amazon sont repérés par leur référence ASIN, ne serait-il pas plus pratique de disposer d'un tag de template qui ferait la même chose et que l'on pourrait utiliser de la sorte :

{% amazon_snippet "reference_asin" %}

Voilà qui est plus élégant. Voyons maintenant comment implémenter ce tag amazon_snippet.

Un tag Django personnalisé amazon_snippet pour les produits Amazon

Avant d'écrire le code, comprenons bien les choses. Notre tag aura besoin, pour fonctionner :

  • d'un paramètre asin, via lequel l'utilisateur du tag pourra spécifier la référence du produit qu'il souhaite afficher ;
  • éventuellement de la référence affilié de l'utilisateur du tag (et oui, il faut bien faire un peu de business comme on peut).

Voici le code de notre tag perso Amazon.

context_processor.py
from django.conf import settings

def amazon_snippet(context, asin):
    """
    Tag permettant d'afficher l'image Amazon d'un produit en fonction de son 
    ASIN, avec lien vers la fiche article + tag affilié.
    """
    amazon_affiliate_id = settings.AMAZON_ID
    
    offer_url = 'http://www.amazon.fr/gp/product/{asin}/ref=as_li_ss_il?ie=UTF8&camp=1642&creative=19458&creativeASIN={asin}&linkCode=as2&tag={amazon_affiliate_id}'.format(asin=asin, amazon_affiliate_id=amazon_affiliate_id)
    image_url = 'http://ws-eu.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN={asin}&Format=_SL160_&ID=AsinImage&MarketPlace=FR&ServiceVersion=20070822&WS=1&tag={amazon_affiliate_id}'.format(asin=asin, amazon_affiliate_id=amazon_affiliate_id)
    
    snippet = '<a href="{offer_url}"><img src="{image_url}" alt="Produit Amazon" /></a>'.format(offer_url=offer_url, image_url=image_url)
    return snippet

Quelques remarques concernant ce tag perso Amazon :

  • Pour trouver l'ID affilié de l'utilisateur, notre fonction fait appel à la configuration du projet via settings : il faut obligatoirement ajouter, dans le fichier settings.py, une constante nommée AMAZON_ID, qui doit contenir l'ID affilié. Laissé en exercice : il est bien sûr possible de modifier le code ci-dessus pour tester si la constante AMAZON_ID est définie ou non dans settings.py, et gérer le cas où elle ne l'est pas (par exemple, en créant une URL sans le paramètre tag…).
  • Nous construisons l'URL de la fiche article (offer_url) ainsi que l'URL de l'image du produit à afficher (image_url) en utilisant la fonction format expliquée dans l'introduction à Python, formattage de chaînes de caractères.
  • Notre fonction tag perso retourne une chaîne de caractère : l'appel du tag sera remplacé, à l'exécution, dans la vue (template), par le contenu de cette chaîne, tout simplement.

Est-ce qu'il marche, ce tag personnalisé Amazon Django ?

Le site de cette formation Django utilise une version analogue du tag défini ci-dessus. Voici le résultat :

Article

Et voici le code de l'appel, dans la vue (template) :

page.html
{% amazon_snippet "2212134150" %}