Le langage de gabarit de Django : pour les programmeurs Python¶
Ce document prĂ©sente le systĂšme de gabarits de Django dans une perspective technique : son fonctionnement et ses possibilitĂ©s dâextension. Si vous recherchez simplement la rĂ©fĂ©rence de la syntaxe du langage, consultez Le langage de gabarit de Django.
Il prĂ©suppose une comprĂ©hension des gabarits, des contextes, des variables, des balises et du rendu des gabarits. Commencez par lâintroduction au langage de gabarit de Django si ces concepts ne vous sont pas familiers.
Aperçu¶
Lâutilisation du systĂšme de gabarits en Python est un processus Ă trois Ă©tapes :
- Vous configurez un moteur
Engine. - Vous compilez le code du gabarit en un objet
Template. - Vous produisez ce gabarit en fonction dâun
Context.
Les projets Django se basent gĂ©nĂ©ralement sur lâAPI de haut niveau et indĂ©pendante du moteur pour chacune de ces Ă©tapes plutĂŽt que dâemployer lâAPI de bas niveau du systĂšme des gabarits :
- Pour chaque moteur
DjangoTemplatesdu rĂ©glageTEMPLATES, Django crĂ©e une instanceEngine.DjangoTemplatesenglobeEngineet lâadapte Ă lâAPI commune des moteurs de gabarits. - Le module
django.template.loaderfournit des fonctions telles queget_template()pour le chargement des gabarits. Elles renvoient undjango.template.backends.django.Templatequi adapte lâobjetdjango.template.TemplaterĂ©el. - Le gabarit
Templateobtenu Ă lâĂ©tape prĂ©cĂ©dente possĂšde une mĂ©thoderender()qui produit un contexte et Ă©ventuellement une requĂȘte dans un objetContextet dĂ©lĂšgue le rendu Ă lâobjetTemplatesous-jacent.
Configuration dâun moteur¶
Si vous utilisez simplement le moteur DjangoTemplates, cette documentation nâest probablement pas celle que vous cherchez. Une instance de la classe Engine dĂ©crite ci-dessous est accessible en utilisant lâattribut engine du moteur, et toute valeur par dĂ©faut dâattribut mentionnĂ©e plus bas est remplacĂ©e par ce qui est transmis par DjangoTemplates.
-
class
Engine(dirs=None, app_dirs=False, context_processors=None, debug=False, loaders=None, string_if_invalid='', file_charset='utf-8', libraries=None, builtins=None, autoescape=True)[source]¶ Lors de la crĂ©ation dâune instance de
Engine, tous les paramĂštres doivent ĂȘtre transmis sous forme de paramĂštres nommĂ©s :dirsdĂ©finit une liste de rĂ©pertoires dans lesquels le moteur recherche des fichiers sources de gabarits. Cette liste est utilisĂ©e pour configurerfilesystem.Loader.La valeur par dĂ©faut est une liste vide.
app_dirsnâaffecte que la valeur par dĂ©faut deloaders. Voir ci-dessous.Sa valeur par dĂ©faut est
False.autoescapecontrĂŽle si lâauto-Ă©chappement HTML est activĂ©.Sa valeur par dĂ©faut est
True.Avertissement
Ne la mettez Ă
Falseque si vous produisez des gabarits non HTML !context_processorsest une liste de chemins Python pointĂ©s vers des objets exĂ©cutables utilisĂ©s pour remplir le contexte lorsquâun gabarit est produit avec une requĂȘte. Ces exĂ©cutables acceptent un objet requĂȘte comme paramĂštre et renvoient un dictionnaire dâĂ©lĂ©ments Ă fusionner dans le contexte.La valeur par dĂ©faut est une liste vide.
Voir
RequestContextpour plus dâinformations.debugest une valeur boolĂ©enne qui active ou dĂ©sactive le mode dĂ©bogage des gabarits. Quand elle vautTrue, le moteur de gabarit stocke des informations de dĂ©bogage supplĂ©mentaires pouvant ĂȘtre utilisĂ©es pour afficher un rapport dĂ©taillĂ© lors de toute exception gĂ©nĂ©rĂ©e durant le rendu des gabarits.Sa valeur par dĂ©faut est
False.loadersest une liste de classes de chargeurs de gabarits, sous forme de chaĂźnes. Chaque classeLoadersait comment importer les gabarits dâune source particuliĂšre. Il est possible dâindiquer des tuples au lieu de chaĂźnes. Le premier Ă©lĂ©ment du tuple correspond au nom de classe deLoaderalors que les Ă©lĂ©ments suivants seront transmis Ă la classeLoaderen vue de son initialisation.Sa valeur par dĂ©faut est une liste contenant :
'django.template.loaders.filesystem.Loader''django.template.loaders.app_directories.Loader'si et seulement siapp_dirsvautTrue.
Si
debugvautFalse, ces chargeurs sont enveloppés pardjango.template.loaders.cached.Loader.Voir Types de chargeurs pour les détails.
Changed in Django 1.11:Lâactivation du chargeur de gabarit avec cache lorsque
debugvautFalsea été ajouté.string_if_invalidest le résultat, sous forme de chaßne de caractÚres, que le systÚme des gabarits utilise pour remplacer le contenu de variables non valides (par ex. mal orthographiées).Sa valeur par défaut est une chaßne vide.
Voir Traitement des variables non valides pour les détails.
file_charsetest le jeu de caractÚres utilisé pour lire les fichiers de gabarits depuis le disque.Sa valeur par défaut est
'utf-8'.'libraries': un dictionnaire dâĂ©tiquettes et de chemins Python pointĂ©s de modules de balises de gabarit Ă inscrire auprĂšs du moteur de gabarit. Ceci est utilisĂ© pour ajouter de nouvelles bibliothĂšques ou pour fournir des Ă©tiquettes alternatives Ă celles qui existent. Par exemple :Engine( libraries={ 'myapp_tags': 'path.to.myapp.tags', 'admin.urls': 'django.contrib.admin.templatetags.admin_urls', }, )
Les bibliothĂšques peuvent ĂȘtre chargĂ©es en passant la clĂ© de dictionnaire correspondante Ă la balise
{% load %}.'builtins': une liste de chemins Python pointés de modules de balises de gabarit à ajouter aux modules intégrés. Par exemple :Engine( builtins=['myapp.builtins'], )
Les balises et les filtres des bibliothĂšques intĂ©grĂ©es peuvent ĂȘtre utilisĂ©s sans devoir dâabord faire appel Ă la balise
{% load %}.
-
static
Engine.get_default()[source]¶ Renvoie le moteur
Enginesous-jacent du premier moteurDjangoTemplatesconfigurĂ©. GĂ©nĂšreImproperlyConfiguredsi aucun moteur nâa Ă©tĂ© configurĂ©.Câest obligatoire pour prĂ©server les API qui comptent sur un moteur configurĂ© implicitement et globalement disponible. Toute autre utilisation est fortement dĂ©couragĂ©e.
Changed in Django 2.0:Dans les précédentes versions,
ImproperlyConfiguredétait aussi générée si plusieurs moteurs étaient configurés, au lieu de renvoyer le premier.
-
Engine.from_string(template_code)[source]¶ Compile le code du gabarit donné et renvoie un objet
Template.
-
Engine.get_template(template_name)[source]¶ Charge un gabarit ayant le nom donné, le compile et renvoie un objet
Template.
-
Engine.select_template(template_name_list)[source]¶ Comme
get_template(), sauf quâil accepte une liste de noms et renvoie le premier gabarit existant de la liste.
Chargement dâun gabarit¶
La maniĂšre recommandĂ©e de crĂ©er un Template est dâappeler les mĂ©thodes de fabrication du moteur Engine: get_template(), select_template() et from_string().
Dans un projet Django oĂč le rĂ©glage TEMPLATES dĂ©finit un moteur DjangoTemplates, il est possible dâinstancier directement un objet Template. Si plus dâun moteur DjangoTemplates est dĂ©fini, câest le premier qui sera utilisĂ©.
-
class
Template[source]¶ Cette classe se trouve dans
django.template.Template. Le constructeur accepte un paramĂštre, le code brut du gabarit :from django.template import Template template = Template("My name is {{ my_name }}.")
En coulisses
Le systĂšme nâanalyse quâune seule fois le code brut du gabarit, au moment de la crĂ©ation de lâobjet Template. Par la suite, le rĂ©sultat est stockĂ© en interne sous forme de structure arborescente pour des raisons de performance.
MĂȘme lâanalyse en soi est assez rapide. La plupart de lâanalyse se dĂ©roule dans un seul appel Ă une seule et courte expression rĂ©guliĂšre.
Rendu dâun contexte¶
Ă partir du moment oĂč vous avez un objet Template compilĂ©, vous pouvez procĂ©der au rendu dâun contexte. Vous pouvez rĂ©utiliser le mĂȘme gabarit pour le produire Ă plusieurs reprises avec diffĂ©rents contextes.
-
class
Context(dict_=None)[source]¶ Le constructeur de
django.template.Contextaccepte un paramĂštre facultatif â un dictionnaire faisant correspondre des noms de variables Ă leurs valeurs.Pour plus de dĂ©tails, voir Manipulation des objets Context plus bas.
-
Template.render(context)[source]¶ Appelez la méthode
render()de lâobjetTemplateavec unContextqui doit « remplir » le gabarit :>>> from django.template import Context, Template >>> template = Template("My name is {{ my_name }}.") >>> context = Context({"my_name": "Adrian"}) >>> template.render(context) "My name is Adrian." >>> context = Context({"my_name": "Dolores"}) >>> template.render(context) "My name is Dolores."
Variables et sous-éléments¶
Les noms de variables peuvent contenir des lettres (A-Z), des chiffres (0-9), des soulignements et des points (mais elles ne peuvent pas commencer par un soulignement).
Les points ont une signification particuliĂšre dans le rendu des gabarits. Un point dans un nom de variable indique lâaccĂšs Ă un sous-Ă©lĂ©ment. Plus prĂ©cisĂ©ment, lorsque le systĂšme de gabarit voit un point dans un nom de variable, il recherche des sous-Ă©lĂ©ments dans cet ordre :
- AccĂšs dictionnaire. Exemple :
foo["bar"] - AccĂšs attribut. Exemple :
foo.bar - AccĂšs par index de liste. Exemple :
foo[bar]
Notez que « bar » dans une expression de gabarit comme {{ foo.bar }} est interprĂ©tĂ© comme une chaĂźne littĂ©rale et mĂȘme si une variable « bar » existe dans le contexte du gabarit, elle ne sera pas appelĂ©e.
Le systĂšme de gabarits utilise le premier accĂšs qui fonctionne. Câest une logique de court-circuit. Voici quelques exemples :
>>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
>>> t.render(Context(d))
"My name is Joe."
>>> class PersonClass: pass
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
>>> t.render(Context({"person": p}))
"My name is Ron."
>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."
Si un Ă©lĂ©ment de la variable est un objet exĂ©cutable, le systĂšme de gabarits essaye de lâappeler. Exemple :
>>> class PersonClass2:
... def name(self):
... return "Samantha"
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
Les variables exĂ©cutables sont lĂ©gĂšrement plus complexes que les variables qui ne demandent que des accĂšs directs. Voici quelques Ă©lĂ©ments Ă garder en tĂȘte :
Si la variable gĂ©nĂšre une exception quand elle est appelĂ©e, celle-ci est propagĂ©e, sauf si lâexception possĂšde un attribut
silent_variable_failurevalantTrue. Dans ce dernier cas, la variable produira une chaĂźne Ă©quivalente au contenu de lâoption de configurationstring_if_invaliddu moteur (chaĂźne vide par dĂ©faut). Exemple :>>> t = Template("My name is {{ person.first_name }}.") >>> class PersonClass3: ... def first_name(self): ... raise AssertionError("foo") >>> p = PersonClass3() >>> t.render(Context({"person": p})) Traceback (most recent call last): ... AssertionError: foo >>> class SilentAssertionError(Exception): ... silent_variable_failure = True >>> class PersonClass4: ... def first_name(self): ... raise SilentAssertionError >>> p = PersonClass4() >>> t.render(Context({"person": p})) "My name is ."
Notez que
django.core.exceptions.ObjectDoesNotExist, qui est la classe de base de toutes les exceptionsDoesNotExistde lâAPI de base de donnĂ©es de Django, contientsilent_variable_failure = True. Ainsi, si vous utilisez les gabarits de Django avec des objets modĂšles de Django, toute exceptionDoesNotExistĂ©choue silencieusement.Une variable ne peut ĂȘtre appelĂ©e que si elle ne demande pas de paramĂštre. Sinon le systĂšme renvoie la valeur de lâoption
string_if_invaliddu moteur.
Il est clair quâil peut exister des effets de bord lors de lâappel Ă certaines variables et il serait insensĂ© ou sĂ©curitairement dĂ©sastreux de permettre au systĂšme de gabarits dây accĂ©der.
Un bon exemple est la méthode
delete()de chaque objet modĂšle de Django. Le systĂšme de gabarits ne devrait pas permettre de faire quelque chose comme :I will now delete this valuable data. {{ data.delete }}
Pour empĂȘcher cela, dĂ©finissez un attribut
alters_datasur la variable exĂ©cutable. Le systĂšme de gabarits nâappellera pas une variable si elle contientalters_data=Trueet la remplace plutĂŽt par le contenu destring_if_invalid, sans conditions. Les mĂ©thodes gĂ©nĂ©rĂ©es dynamiquementdelete()etsave()sur les objets modĂšles de Django reçoivent automatiquementalters_data=True. Exemple :def sensitive_function(self): self.database_record.delete() sensitive_function.alters_data = True
Vous pouvez parfois avoir envie de dĂ©sactiver cette fonctionnalitĂ© pour dâautres raisons, et dire au systĂšme de gabarits de ne pas interprĂ©ter une variable, peu importe le contexte. Pour ce faire, il faut dĂ©finir un attribut
do_not_call_in_templatessur la variable exĂ©cutable, avec la valeurTrue. Le systĂšme de gabarits va alors considĂ©rer que la variable ne peut pas ĂȘtre appelĂ©e (ce qui permet par exemple dâaccĂ©der aux attributs de lâobjet exĂ©cutable).
Traitement des variables non valides¶
GĂ©nĂ©ralement, si une variable nâexiste pas, le systĂšme des gabarits insĂšre la valeur de lâoption de configuration string_if_invalid du moteur, qui vaut '' (chaĂźne vide) par dĂ©faut.
Les filtres appliqués à une variable non valide ne seront appliqués que si string_if_invalid est défini à '' (la chaßne vide). Si string_if_invalid est défini à une autre valeur, les filtres de variable seront ignorés.
Ce comportement est lĂ©gĂšrement diffĂ©rent pour les balises de gabarit if, for et regroup. Si une variable non valide est fournie Ă lâune de ces balises de gabarit, la variable sera interprĂ©tĂ©e comme None. Les filtres sont toujours appliquĂ©s aux variables non valides dans ces balises de gabarit.
Si string_if_invalid contient un substituant '%s', ce dernier sera remplacé par le nom de la variable non valide.
à des fins de débogage uniquement !
Bien que string_if_invalid puisse ĂȘtre un outil de dĂ©bogage utile, il nâest pas conseillĂ© de lâactiver de maniĂšre permanente durant le dĂ©veloppement.
Beaucoup de gabarits, y compris ceux du site dâadministration, comptent sur le comportement silencieux du systĂšme de gabarit lorsquâune variable non existante apparaĂźt. Si string_if_invalid contient une valeur autre que '', vous allez rencontrer des problĂšmes dâaffichage avec ces gabarits et ces sites.
GĂ©nĂ©ralement, string_if_invalid ne devrait ĂȘtre activĂ© que pour dĂ©boguer un problĂšme spĂ©cifique dâun gabarit, puis rĂ©initialisĂ© une fois cette phase terminĂ©e.
Variables intégrées¶
Tous les contextes contiennent True, False et None. Comme on peut sây attendre, ces variables correspondent aux objets Python Ă©quivalents.
Restrictions avec les chaßnes littérales¶
Le langage de gabarit de Django ne possÚde pas de moyen pour échapper les caractÚres utilisés pour sa propre syntaxe. Par exemple, la balise templatetag est indispensable pour afficher des séquences de caractÚres comme {% ou %}.
Un problĂšme similaire survient lorsquâil sâagit dâinclure ces sĂ©quences dans les paramĂštres dâun filtre ou dâune balise. Par exemple, lors de lâanalyse dâun bloc de balise, lâanalyseur de gabarit de Django cherche la premiĂšre occurrence de %} aprĂšs un {%. Cela empĂȘche de pouvoir utiliser "%}" dans une chaĂźne littĂ©rale. Par exemple, une exception TemplateSyntaxError est gĂ©nĂ©rĂ©e pour les expressions suivantes :
{% include "template.html" tvar="Some string literal with %} in it." %}
{% with tvar="Some string literal with %} in it." %}{% endwith %}
La mĂȘme problĂ©matique est rĂ©vĂ©lĂ©e quand on utilise une sĂ©quence rĂ©servĂ©e dans les paramĂštres dâun filtre :
{{ some.variable|default:"}}" }}
Si vous avez besoin dâutiliser des chaĂźnes qui contiennent ces sĂ©quences, vous devez les stocker dans des variables de gabarit ou utiliser une balise ou un filtre personnalisĂ© pour dĂ©tourner cette restriction.
Manipulation des objets Context¶
La plupart du temps, les objets Context sont créés en transmettant Ă Context() un dictionnaire contenant les donnĂ©es utiles. Mais il est toujours possible dâajouter ou dâenlever des Ă©lĂ©ments dâun objet Context aprĂšs sa crĂ©ation, en employant la syntaxe habituelle des dictionnaires :
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'
-
Context.get(key, otherwise=None)¶ Renvoie la valeur correspondant Ă
keysikeyest dans le contexte, sinon renvoieotherwise.
-
Context.setdefault(key, default=None)¶ Si
keyest dans le contexte, renvoie sa valeur. Sinon insĂšrekeyavec la valeurdefaultet renvoiedefault.
-
Context.pop()¶
-
Context.push()¶
Un objet Context est une pile. Câest-Ă -dire que vous pouvez lui appliquer les mĂ©thodes push() et pop(). En cas de pop() en trop, une exception django.template.ContextPopException est gĂ©nĂ©rĂ©e :
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.push()
{}
>>> c['foo'] = 'second level'
>>> c['foo']
'second level'
>>> c.pop()
{'foo': 'second level'}
>>> c['foo']
'first level'
>>> c['foo'] = 'overwritten'
>>> c['foo']
'overwritten'
>>> c.pop()
Traceback (most recent call last):
...
ContextPopException
Vous pouvez aussi utiliser push() comme gestionnaire de contexte pour garantir que lâinstruction pop() correspondante soit effectivement appelĂ©e.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push():
... c['foo'] = 'second level'
... c['foo']
'second level'
>>> c['foo']
'first level'
Tous les paramÚtres passés à push() sont transmis au constructeur de dict utilisé pour construire le nouveau niveau de contexte.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.push(foo='second level'):
... c['foo']
'second level'
>>> c['foo']
'first level'
En plus de push() et pop(), lâobjet Context dĂ©finit Ă©galement une mĂ©thode update(). Elle fonctionne comme push(), mais accepte en paramĂštre un dictionnaire et place ce dictionnaire sur la pile, au lieu dâun dictionnaire vide.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'foo': 'updated'})
{'foo': 'updated'}
>>> c['foo']
'updated'
>>> c.pop()
{'foo': 'updated'}
>>> c['foo']
'first level'
Comme push(), vous pouvez utiliser update() comme gestionnaire de contexte pour garantir que lâinstruction pop() correspondante soit effectivement appelĂ©e.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> with c.update({'foo': 'second level'}):
... c['foo']
'second level'
>>> c['foo']
'first level'
Lâutilisation de Context comme une pile est bien pratique avec certaines balises de gabarit personnalisĂ©es.
-
Context.flatten()¶
En utilisant la mĂ©thode flatten(), vous pouvez obtenir lâensemble de la pile de Context sous forme dâun unique dictionnaire, y compris les variables natives.
>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'bar': 'second level'})
{'bar': 'second level'}
>>> c.flatten()
{'True': True, 'None': None, 'foo': 'first level', 'False': False, 'bar': 'second level'}
La méthode flatten() est aussi utilisée en interne pour rendre les objets Context comparables.
>>> c1 = Context()
>>> c1['foo'] = 'first level'
>>> c1['bar'] = 'second level'
>>> c2 = Context()
>>> c2.update({'bar': 'second level', 'foo': 'first level'})
{'foo': 'first level', 'bar': 'second level'}
>>> c1 == c2
True
Le rĂ©sultat de flatten() peut ĂȘtre utile dans les tests unitaires pour comparer Context avec un dict:
class ContextTest(unittest.TestCase):
def test_against_dictionary(self):
c1 = Context()
c1['update'] = 'value'
self.assertEqual(c1.flatten(), {
'True': True,
'None': None,
'False': False,
'update': 'value',
})
Utilisation de RequestContext¶
Django contient une classe Context spĂ©ciale, django.template.RequestContext, qui se comporte lĂ©gĂšrement diffĂ©remment de lâobjet django.template.Context normal. La premiĂšre diffĂ©rence est quâelle demande un objet HttpRequest comme premier paramĂštre. Par exemple :
c = RequestContext(request, {
'foo': 'bar',
})
La seconde diffĂ©rence est quâelle remplit automatiquement le contexte avec quelques variables, en fonction de lâoption de configuration context_processors du moteur.
Lâoption context_processors est une liste dâobjets exĂ©cutables appelĂ©s processeurs de contexte qui acceptent un objet requĂȘte en paramĂštre et renvoient un dictionnaire dâĂ©lĂ©ments Ă fusionner dans le contexte. Dans le fichier de rĂ©glages gĂ©nĂ©rĂ© par dĂ©faut, le moteur de gabarit par dĂ©faut contient les processeurs de contexte suivants :
[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
En plus de ce contenu, RequestContext active toujours 'django.template.context_processors.csrf'. Il sâagit dâun processeur de contexte liĂ© Ă la sĂ©curitĂ© exigĂ© par lâapplication dâadministration ainsi que dâautres applications contribuĂ©es. Il est volontairement ajoutĂ© de force pour quâil ne puisse pas ĂȘtre enlevĂ© par une erreur de configuration dans lâoption context_processors.
Chaque processeur est appliquĂ© successivement. Cela signifie que si un processeur ajoute une variable au contexte et que le processeur suivant ajoute une variable de mĂȘme nom, la seconde Ă©crase la premiĂšre. Les processeurs par dĂ©faut sont prĂ©sentĂ©s ci-dessous.
Quand les processeurs de contexte sont-ils appliqués ?
Les processeurs de contexte sont appliquĂ©s au sommet des donnĂ©es de contexte. Cela signifie quâun processeur de contexte peut Ă©craser une variable que vous avez fournie dans un objet Context ou RequestContext, il faut donc faire attention de ne pas utiliser des variables dont le nom peut entrer en conflit avec ceux des processeurs de contexte installĂ©s.
Si vous souhaitez que des données de contexte aient la priorité sur les processeurs de contexte, utilisez le schéma suivant :
from django.template import RequestContext
request_context = RequestContext(request)
request_context.push({"my_name": "Adrian"})
Django fait cela pour permettre aux donnĂ©es de contexte dâĂ©craser des processeurs de contexte dans des API comme render() ou TemplateResponse.
Il est Ă©galement possible de donner Ă RequestContext une liste de processeurs supplĂ©mentaires en utilisant le troisiĂšme paramĂštre positionnel facultatif, processors. Dans cet exemple, lâinstance RequestContext reçoit une variable ip_address:
from django.http import HttpResponse
from django.template import RequestContext, Template
def ip_address_processor(request):
return {'ip_address': request.META['REMOTE_ADDR']}
def client_ip_view(request):
template = Template('{{ title }}: {{ ip_address }}')
context = RequestContext(request, {
'title': 'Your IP Address',
}, [ip_address_processor])
return HttpResponse(template.render(context))
Processeurs de contexte de gabarit intégrés¶
Voici ce que font chacun des processeurs de contexte intégrés :
django.contrib.auth.context_processors.auth¶
Si ce processeur est activé, chaque RequestContext contiendra ces variables :
userâ une instanceauth.UserreprĂ©sentant lâutilisateur actuellement connectĂ© (ou une instanceAnonymousUser, si le client nâest pas connectĂ©).permsâ une instance dedjango.contrib.auth.context_processors.PermWrapper, reprĂ©sentant les permissions de lâutilisateur actuellement connectĂ©.
django.template.context_processors.debug¶
Si ce processeur est activĂ©, chaque RequestContext contient ces deux variables â mais seulement si le rĂ©glage DEBUG vaut True et que lâadresse IP de la requĂȘte (request.META['REMOTE_ADDR']) se trouve dans le rĂ©glage INTERNAL_IPS:
debugâTrue. Vous pouvez lâutiliser dans les gabarits pour tester si vous ĂȘtes en modeDEBUG.sql_queriesâ une liste de dictionnaires{'sql': ..., 'time': ...}reprĂ©sentant chaque requĂȘte SQL effectuĂ©e jusque-lĂ dans le traitement de la requĂȘte et le temps nĂ©cessaire Ă son exĂ©cution. La liste est triĂ©e par alias de base de donnĂ©es, puis par requĂȘte. Elle est produite de maniĂšre diffĂ©rĂ©e au moment de son accĂšs.
django.template.context_processors.i18n¶
Si ce processeur est activé, chaque RequestContext contiendra ces deux variables :
LANGUAGESâ la valeur du rĂ©glageLANGUAGES.LANGUAGE_CODEârequest.LANGUAGE_CODE, si elle existe. Sinon, la valeur du rĂ©glageLANGUAGE_CODE.
Voir Internationalisation et régionalisation pour plus de détails.
django.template.context_processors.media¶
Si ce processeur est activé, chaque RequestContext contiendra une variable MEDIA_URL, équivalente au réglage MEDIA_URL.
django.template.context_processors.static¶
Si ce processeur est activé, chaque RequestContext contiendra une variable STATIC_URL, équivalente au réglage STATIC_URL.
django.template.context_processors.csrf¶
Ce processeur ajoute un jeton requis par la balise de gabarit csrf_token pour se protéger des attaques de type Cross Site Request Forgeries.
django.template.context_processors.request¶
Si ce processeur est activĂ©, chaque RequestContext contiendra une variable request correspondant Ă lâobjet HttpRequest actuel.
django.template.context_processors.tz¶
Si ce processeur est activé, chaque RequestContext contiendra une variable TIME_ZONE, fournissant le nom du fuseau horaire actuellement actif.
django.contrib.messages.context_processors.messages¶
Si ce processeur est activé, chaque RequestContext contiendra ces deux variables :
messagesâ une liste de messages (sous forme de chaĂźnes) qui ont Ă©tĂ© dĂ©finis au travers de lâinfrastructure des messages.DEFAULT_MESSAGE_LEVELSâ un tableau de correspondance entre les noms de niveaux de message et leur valeur numĂ©rique.
Ăcriture de son propre processeur de contexte¶
Un processeur de contexte possĂšde une interface trĂšs simple : il sâagit dâune fonction Python acceptant un paramĂštre, un objet HttpRequest, et renvoyant un dictionnaire qui est ensuite ajoutĂ© au contexte de gabarit. Chaque processeur de contexte doit renvoyer un dictionnaire.
Les processeurs de contexte personnalisĂ©s peuvent se trouver nâimporte oĂč dans le code. Tout ce que Django demande, câest que lâoption 'context_processors' du rĂ©glage TEMPLATES (ou le paramĂštre context_processors dâun moteur Engine si vous lâutilisez directement) contienne le chemin vers le processeur personnalisĂ©.
Chargement des gabarits¶
En gĂ©nĂ©ral, il est conseillĂ© de stocker les gabarits sur le systĂšme de fichiers plutĂŽt que de faire appel Ă lâAPI Template de bas niveau. Les gabarits doivent se trouver dans un rĂ©pertoire dĂ©signĂ© comme rĂ©pertoire de gabarits.
Django recherche les rĂ©pertoires de gabarits Ă plusieurs endroits, en fonction des rĂ©glages de chargement des gabarits (voir « Types de chargeurs » ci-dessous), mais la façon la plus Ă©lĂ©mentaire de dĂ©signer des rĂ©pertoires de gabarits est dâutiliser lâoption DIRS.
Lâoption DIRS¶
Indiquez Ă Django quels sont vos rĂ©pertoires de gabarits en utilisant lâoption DIRS du rĂ©glage TEMPLATES dans votre fichier de rĂ©glages, ou le paramĂštre dirs de Engine. Il devrait contenir une liste de chaĂźnes contenant les chemins complets vers les rĂ©pertoires de gabarits :
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'/home/html/templates/lawrence.com',
'/home/html/templates/default',
],
},
]
Les gabarits peuvent se trouver nâimporte oĂč, pour autant que leur emplacement soit lisible par le serveur Web. Leur extension est Ă©galement Ă votre bon plaisir, .html, .txt, ou mĂȘme sans extension du tout.
Notez que ces chemins doivent utiliser les barres obliques de style Unix, mĂȘme avec Windows.
Types de chargeurs¶
Par dĂ©faut, Django utilise un chargeur de gabarit basĂ© sur le systĂšme de fichiers, mais il existe Ă©galement quelques autres chargeurs de gabarit, qui savent comment charger des gabarits Ă partir dâautres sources.
Certains de ces autres chargeurs sont dĂ©sactivĂ©s par dĂ©faut, mais vous pouvez les activer en ajoutant une option 'loaders' Ă votre moteur DjangoTemplates dans le rĂ©glage TEMPLATES ou en transmettant un paramĂštre loaders Ă Engine. loaders doit contenir une liste de chaĂźnes ou de tuples, oĂč chaque Ă©lĂ©ment reprĂ©sente une classe de chargeur de gabarit. Voici les chargeurs de gabarit que Django propose :
django.template.loaders.filesystem.Loader
-
class
filesystem.Loader¶ Charge les gabarits à partir du systÚme de fichiers, en fonction de
DIRS.Ce chargeur est actif par dĂ©faut. Cependant, il ne trouvera aucun gabarit tant que vous nâaurez pas dĂ©fini
DIRSĂ une liste non vide :TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], }]
Il est aussi possible de surcharger
'DIRS'et de définir des répertoires spécifiques à un chargeur basé sur le systÚme de fichiers :TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ( 'django.template.loaders.filesystem.Loader', [os.path.join(BASE_DIR, 'templates')], ), ], }, }]
Changed in Django 1.11:La possibilité de définir des répertoires spécifiques à un chargeur basé sur le systÚme de fichiers a été ajoutée.
django.template.loaders.app_directories.Loader
-
class
app_directories.Loader¶ Charge les gabarits Ă partir des dossiers dâapplications Django sur le systĂšme de fichiers. Pour chaque application dans
INSTALLED_APPS, le chargeur cherche un sous-rĂ©pertoire nommĂ©templates. Sâil le trouve, Django recherche les gabarits dans ce rĂ©pertoire.Cela signifie que vous pouvez stocker les gabarits Ă lâintĂ©rieur des diffĂ©rentes applications. Cela facilite Ă©galement la distribution des applications Django dotĂ©es de gabarits par dĂ©faut.
Par exemple, avec ce réglage :
INSTALLED_APPS = ['myproject.polls', 'myproject.music']
âŠ
get_template('foo.html')recherchefoo.htmldans ces rĂ©pertoires, dans lâordre :/chemin/vers/myproject/polls/templates//chemin/vers/myproject/music/templates/
⊠et utilise le premier quâil trouve.
Lâordre de
INSTALLED_APPSest important ! Par exemple, si vous souhaitez personnaliser lâadministration de Django, il peut ĂȘtre utile de surcharger le gabaritadmin/base_site.htmlstandard dedjango.contrib.adminpar votre propreadmin/base_site.htmldansmyproject.polls. Vous devez alors vous assurer quemyproject.pollsapparaisse avantdjango.contrib.admindansINSTALLED_APPS, sinondjango.contrib.adminsera chargĂ© en premier et votre gabarit sera ignorĂ©.Notez que le chargeur effectue une optimisation lors de son premier lancement : il place en cache une liste des paquets
INSTALLED_APPSqui possÚdent un sous-répertoiretemplates.Vous pouvez activer ce chargeur en définissant simplement
APP_DIRSĂTrue:TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'APP_DIRS': True, }]
django.template.loaders.cached.Loader
-
class
cached.Loader¶ Par défaut (lorsque
DEBUGvautTrue), le systĂšme des gabarits lit et compile les gabarits chaque fois quâils sont produits. MĂȘme si le systĂšme des gabarits de Django est assez rapide, la charge de lecture et de compilation des gabarits peut ĂȘtre consĂ©quente.Le chargeur de gabarits « en cache » est configurĂ© en lui donnant une liste dâautres chargeurs quâil va encapsuler. Les chargeurs encapsulĂ©s sont utilisĂ©s pour retrouver les gabarits inconnus la premiĂšre fois quâils sont rĂ©fĂ©rencĂ©s. Le chargeur « en cache » stocke ensuite lâobjet
TemplatecompilĂ© en mĂ©moire. Cette instance mise en cache est renvoyĂ©e lors de chaque nouvelle requĂȘte de chargement de ce mĂȘme gabarit.This loader is automatically enabled if
OPTIONS['loaders']isnât specified andOPTIONS['debug']isFalse(the latter option defaults to the value ofDEBUG).Il est aussi possible dâactiver le cache de gabarits avec des chargeurs de gabarit personnalisĂ©s en utilisant des rĂ©glages comme ceci :
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'OPTIONS': { 'loaders': [ ('django.template.loaders.cached.Loader', [ 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', 'path.to.custom.Loader', ]), ], }, }]
Note
Toutes les balises de gabarit intĂ©grĂ©es Ă Django peuvent ĂȘtre utilisĂ©es sans problĂšme avec le chargeur « en cache », mais si vous utilisez des balises de gabarit personnalisĂ©es provenant de paquets externes ou que vous avez Ă©crites vous-mĂȘme, il est nĂ©cessaire de vĂ©rifier que lâimplĂ©mentation des objets
Nodede chaque balise respecte la concurrence (« thread-safe »). Pour plus dâinformations, consultez les indications sur la concurrence entre fils dâexĂ©cution dans les balises de gabarit.Changed in Django 1.11:Lâactivation automatique du chargeur de gabarit avec cache lorsque
debugvautFalsea été ajoutée.
django.template.loaders.locmem.Loader
-
class
locmem.Loader¶ Charge des gabarits Ă partir dâun dictionnaire Python. Utile pour les tests.
Ce chargeur prend un dictionnaire de gabarits comme premier paramĂštre :
TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'loaders': [ ('django.template.loaders.locmem.Loader', { 'index.html': 'content here', }), ], }, }]
Ce chargeur est désactivé par défaut.
Django utilise les chargeurs de gabarit dans lâordre de leur apparition dans lâoption 'loaders'. Il utilise chaque chargeur jusquâĂ ce quâil trouve une correspondance.
Chargeurs personnalisés¶
Il est possible de charger des gabarits provenant de sources supplémentaires en utilisant des chargeurs de gabarit personnalisés. Les classes personnalisées de Loader doivent hériter de django.template.loaders.base.Loader et définir les méthodes get_contents() et get_template_sources().
Méthodes des chargeurs¶
-
class
Loader[source]¶ Charge des gabarits Ă partir dâune source donnĂ©e, telle que le systĂšme de fichier ou une base de donnĂ©es.
-
get_template_sources(template_name)[source]¶ Une méthode acceptant un nom de gabarit
template_nameet renvoyant une Ă une des instancesOriginpour chaque source possible.Par exemple, le chargeur systĂšme de fichiers pourrait recevoir
'index.html'comme paramĂštretemplate_name. Cette mĂ©thode produirait des origines pour le chemin complet deindex.htmltel quâil devrait apparaĂźtre dans chaque rĂ©pertoire de gabarits que le chargeur inspecte.La mĂ©thode nâa pas besoin de vĂ©rifier que le gabarit existe pour un chemin donnĂ©, mais elle doit sâassurer que le chemin est valide. Par exemple, le chargeur systĂšme de fichiers doit sâassurer que le chemin se trouve bien dans un rĂ©pertoire de gabarits valide.
-
get_contents(origin)¶ Renvoie le contenu dâun gabarit en fonction dâune instance
OrigindonnĂ©e.Câest ici quâun chargeur systĂšme de fichiers lit le contenu Ă partir du systĂšme de fichiers, ou quâun chargeur base de donnĂ©es lit Ă partir de la base de donnĂ©es. Si aucun gabarit existant ne correspond, une erreur
TemplateDoesNotExistdoit ĂȘtre gĂ©nĂ©rĂ©e.
-
get_template(template_name, skip=None)[source]¶ Renvoie un objet
Templatecorrespondant Ătemplate_nameen passant en boucle ce queget_template_sources()renvoie et en appelantget_contents(). Le premier gabarit trouvĂ© est renvoyĂ©. Si aucun nâest trouvĂ©, une exceptionTemplateDoesNotExistest gĂ©nĂ©rĂ©e.Le paramĂštre facultatif
skipest une liste dâorigines Ă ignorer lors de lâextension des gabarits. Cela permet Ă des gabarits dâĂ©tendre dâautres gabarits du mĂȘme nom. Une autre utilitĂ© est dâĂ©viter les erreurs de rĂ©cursion.En gĂ©nĂ©ral, il est suffisant que les chargeurs de gabarit personnalisĂ©s dĂ©finissent
get_template_sources()etget_contents().get_template()nâa gĂ©nĂ©ralement pas besoin dâĂȘtre surchargĂ©e.
-
Création de son propre chargeur
Pour des exemples, lisez le code source des chargeurs intégrés à Django.
Origine de gabarit¶
Les gabarits possÚdent un attribut origin contenant des attributs qui dépendent de la source à partir de laquelle ils ont été chargés.
-
class
Origin(name, template_name=None, loader=None)[source]¶ -
name¶ Le chemin du gabarit tel que renvoyĂ© par le chargeur de gabarit. Pour les chargeurs qui lisent Ă partir du systĂšme de fichiers, il sâagit du chemin complet correspondant au gabarit.
Si le gabarit est instanciĂ© directement plutĂŽt que par lâintermĂ©diaire dâun chargeur de gabarits, ce chemin contient
<unknown_source>(source inconnue).
-
template_name¶ Le chemin relatif du gabarit tel que transmis au chargeur de gabarits.
Si le gabarit est instanciĂ© directement plutĂŽt que par lâintermĂ©diaire dâun chargeur de gabarits, cette valeur vaut
None.
-
loader¶ Lâinstance de chargeur de gabarits qui a construit cette
Origin.Si le gabarit est instanciĂ© directement plutĂŽt que par lâintermĂ©diaire dâun chargeur de gabarits, cette valeur vaut
None.django.template.loaders.cached.Loaderexige que tous les chargeurs quâelle enveloppe dĂ©finissent cet attribut, typiquement en crĂ©ant lâinstanceOriginavecloader=self.
-