• Aucun résultat trouvé

Les contextes de templates

III. Techniques avancées 122

14. Simplifions nos templates : filtres, tags et contextes 151

14.3. Les contextes de templates

Avant d’attaquer les tags, nous allons aborder un autre point essentiel qui est la création de template context processor (ou en français, des processeurs de contextes de templates). Le but destemplate context processor est de préremplir le contexte de la requête et ainsi de disposer de données dans tous les templates de notre projet. Le contexte est l’ensemble des variables disponibles dans votre template. Prenons l’exemple suivant :

1 return render(request, 'blog/archives.html', {'news': news, 'date':

date_actuelle})

Ici, nous indiquons au template les variables news et date_actuellequi seront incorporées au contexte, avec les noms news et date. Cependant, par défaut notre contexte ne contiendra pas que ces variables, il est même possible d’en ajouter davantage, si le besoin se fait sentir.

Pour mieux comprendre l’utilité des contextes, démarrons par un petit exemple.

14.3.1. Un exemple maladroit : afficher la date sur toutes nos pages

Il arrive que vous ayez besoin d’accéder à certaines variables depuis tous vos templates, et que ceux-ci soient enregistrés dans votre base de données, un fichier, un cache, etc. Imaginons que vous souhaitiez afficher dans tous vos templates la date du jour. Une première idée serait de

récupérer la date sur chacune des vues :

1 from django.shortcuts import render 2 from datetime import datetime

34 def accueil(request):

5 date_actuelle = datetime.now()

6 # […] Récupération d'autres données (exemple : une liste de news)

7 return render(request, 'accueil.html', locals()) 89 def contact(request):

10 date_actuelle = datetime.now()

11 return render(request, 'contact.html', locals())

Une fois cela fait, il suffit après d’intégrer la date via {{ date_actuelle }}dans un template parent, à partir duquel tous les autres templates seront étendus. Néanmoins, cette méthode est lourde et répétitive, c’est ici que les processeurs de contextes entrent en jeu.

i

Sachez que l’exemple pris ici n’est pas réellement pertinent puisque Django permet déjà par défaut d’afficher la date avec le tag{% now %}. Néanmoins il s’agit d’un exemple simple et concret qui s’adapte bien à l’explication.

14.3.2. Factorisons encore et toujours

Pour résoudre ce problème, nous allons créer une fonction qui sera appelée à chaque page, et qui se chargera d’incorporer la date dans les données disponibles de façon automatique.

Tout d’abord, créez un fichier Python, que nous appellerons context_processors.py, par convention, dans une de vos applications. Vu que cela concerne tout le projet, il est même conseillé de le créer dans le sous-dossier ayant le même nom que votre projet (crepes_bretonnes dans le cas de ce cours).

Dans ce fichier, nous allons coder une ou plusieurs fonctions, qui renverront des dictionnaires de données que le framework intégrera à tous nos templates. Tout d’abord, écrivons notre fonction qui va récupérer la date actuelle. La fonction ne prend qu’un paramètre, qui est notre déjà très connu objet request. En retour, la fonction renvoie un dictionnaire, contenant les valeurs à intégrer dans les templates, assez similaire au dictionnaire passé à la fonction render pour construire un template. Par exemple :

1 from datetime import datetime 23 def get_infos(request):

4 date_actuelle = datetime.now()

5 return {'date_actuelle': date_actuelle}

Sachez que Djangoexécute d’abord la vue et seulement après le contexte. Faites donc attention à prendre des noms de variables suffisamment explicites et qui ont peu de chances de se retrouver dans vos vues, et donc d’entrer en collision. Si jamais vous appelez une variabledate_actuelle,

elle sera tout simplement écrasée par la fonction ci-dessus.

Il faut maintenant indiquer au framework d’exécuter cette fonction à chaque page. Pour cela, nous allons encore une fois nous plonger dans le fichier settings.py et y définir une nouvelle variable. À chaque page, Django exécute et récupère les dictionnaires de plusieurs fonctions, listées dans la variable TEMPLATE_CONTEXT_PROCESSORS. Par défaut, elle est égale au tuple suivant, qui n’est pas présent dans le fichiersettings.py :

1 TEMPLATE_CONTEXT_PROCESSORS = (

Nous voyons que Django utilise lui-même quelques fonctions, afin de nous fournir quelques variables par défaut. Pour éviter de casser ce processus, il fautrecopier cette liste et juste ajouter à la fin nos fonctions :

Nous pouvons désormais utiliser notre variable date_actuelle dans tous nos templates et afficher fièrement la date sur notre blog :

1 <p>Bonjour à tous, nous sommes le {{ date_actuelle }} et il fait beau en Bretagne !</p>

Et peu importe le template où vous intégrez cette ligne, vous aurez forcément le résultat suivant (si vous n’avez pas de variable date_actuelle dans votre vue correspondante, bien sûr) :

1 Bonjour à tous, nous sommes le 15 novembre 2012 23:58:16 et il fait beau en Bretagne !

14.3.2.1. Petit point technique sur l’initialisation du contexte

Attention : dans ce cours nous avons toujours utilisé render comme retour de nos vues (hormis quelques cas précis où nous avons utilisé HttpResponse). Comme nous l’avions précisé dans le premier chapitre sur les templates, la fonction render est un « raccourci », effectuant plusieurs actions en interne, nous évitant la réécriture de plusieurs lignes de code. Cette méthode prend notamment en charge le fait de charger le contexte !

Cependant, toutes les fonctions de django.shortcut ne le font pas, comme par exemple render_to_response, dont nous n’avons pas parlé et qui fonctionne de la façon suivante pour le cas des archives de notre blog :

1 from django.shortcuts import render_to_response 2 [...]

3 return render_to_response('blog/archives.html', locals())

Si vous rechargez la page, vous remarquerez que la date actuelle a disparu, et que ceci ap-paraît : « Bonjour à tous, nous sommes le et il fait beau en Bretagne ! ». En effet, par défaut render_to_response ne prend pas en compte les fonctions contenues dans TEM PLATE_CONTEXT_PROCESSOR… Pour régler ce problème, il faut à chaque fois ajouter un argu-ment :

1 return render_to_response('blog/archives.html', locals(), context_instance=RequestContext(request))

… ce qui est plus lourd à écrire ! Cependant, certains utilisateurs avancés peuvent préférer cette méthode afin de gérer de façon précise le contexte à utiliser.

Faites donc attention à vos contextes si jamais vous vous écartez de la fonction render.