Modèles

Flask utilise Jinja2 comme moteur de modèles. Vous êtes évidemment libre d’utiliser un autre moteur de modèles, mais vous devez toujours installer Jinja2 pour faire fonctionner Flask lui-même. Cette exigence est nécessaire pour permettre des extensions riches. Une extension peut dépendre de la présence de Jinja2.

Cette section ne donne qu’une introduction très rapide sur la façon dont Jinja2 est intégré dans Flask. Si vous voulez des informations sur la syntaxe du moteur de modèles lui-même, rendez-vous sur le site officiel Jinja2 Template Documentation pour plus d’informations.

Configuration de Jinja

A moins d’être personnalisé, Jinja2 est configuré par Flask comme suit :

  • L’auto-échappement est activé pour tous les modèles se terminant par .html, .htm, .xml ainsi que .xhtml lors de l’utilisation de render_template().

  • L’auto-échappement est activé pour toutes les chaînes de caractères lors de l’utilisation de render_template_string().

  • Un modèle a la possibilité d’activer ou de désactiver l’auto-échappement à l’aide de la balise {% autoescape %}.

  • Flask insère quelques fonctions et aides globales dans le contexte Jinja2, en plus des valeurs présentes par défaut.

Contexte standard

Les variables globales suivantes sont disponibles par défaut dans les modèles Jinja2 :

config

L’objet de configuration actuel (flask.Flask.config)

Changelog

Modifié dans la version 0.10: Cette fonction est désormais toujours disponible, même dans les modèles importés.

Nouveau dans la version 0.6.

request

L’objet de requête actuel (flask.request). Cette variable n’est pas disponible si le modèle a été rendu sans contexte de requête actif.

session

L’objet de session actuel (flask.session). Cette variable n’est pas disponible si le modèle a été rendu sans contexte de requête actif.

g

L’objet lié à la requête pour les variables globales (flask.g). Cette variable n’est pas disponible si le modèle a été rendu sans contexte de requête actif.

url_for()

La fonction flask.url_for().

get_flashed_messages()

La fonction flask.get_flashed_messages().

Le comportement du contexte Jinja

Ces variables sont ajoutées au contexte des variables, ce ne sont pas des variables globales. La différence est que par défaut, elles n’apparaîtront pas dans le contexte des modèles importés. Ceci est en partie dû à des considérations de performance, et en partie pour garder les choses explicites.

Qu’est-ce que cela signifie pour vous ? Si vous voulez importer une macro qui doit accéder à l’objet de requête, vous avez deux possibilités :

  1. vous passez explicitement la requête à la macro en tant que paramètre, ou l’attribut de l’objet de la requête qui vous intéresse.

  2. vous importez la macro « avec le contexte ».

L’importation avec le contexte ressemble à ceci :

{% from '_helpers.html' import my_macro with context %}

Contrôle de l’auto-échappement

L’auto-échappement est le concept d’échappement automatique des caractères spéciaux pour vous. Les caractères spéciaux au sens de HTML (ou XML, et donc XHTML) sont &, >, <, " ainsi que '. Comme ces caractères ont des significations spécifiques dans les documents, vous devez les remplacer par des « entités » si vous voulez les utiliser pour le texte. Ne pas le faire ne causerait pas seulement la frustration des utilisateurs par l’impossibilité d’utiliser ces caractères dans le texte, mais peut également conduire à des problèmes de sécurité. (voir Cross-Site Scripting (XSS))

Parfois, cependant, vous devrez désactiver l’auto-échappement dans les modèles. Cela peut être le cas si vous voulez injecter explicitement du HTML dans les pages, par exemple si elles proviennent d’un système qui génère du HTML sécurisé comme un convertisseur markdown vers HTML.

Il y a trois façons d’y parvenir :

  • Dans le code Python, enveloppez la chaîne HTML dans un objet Markup avant de le passer au modèle. C’est en général la méthode recommandée.

  • À l’intérieur du modèle, utilisez le filtre |safe pour marquer explicitement une chaîne comme étant du HTML sûr ({{monvariable|safe }})

  • Désactiver temporairement le système d’auto-échappement.

Pour désactiver le système d’auto-échappement dans les modèles, vous pouvez utiliser le bloc {% autoescape %} :

{% autoescape false %}
    <p>autoescaping is disabled here
    <p>{{ will_not_be_escaped }}
{% endautoescape %}

Si vous le faites, soyez très prudent quant aux variables que vous utilisez dans ce bloc.

Enregistrement des filtres

Si vous voulez enregistrer vos propres filtres dans Jinja2, vous avez deux façons de le faire. Vous pouvez soit les mettre à la main dans le jinja_env de l’application, soit utiliser le décorateur template_filter().

Les deux exemples suivants fonctionnent de la même manière et inversent tous deux un objet :

@app.template_filter('reverse')
def reverse_filter(s):
    return s[::-1]

def reverse_filter(s):
    return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter

Dans le cas du décorateur, l’argument est optionnel si vous voulez utiliser le nom de la fonction comme nom du filtre. Une fois enregistré, vous pouvez utiliser le filtre dans vos modèles de la même manière que les filtres intégrés de Jinja2, par exemple si vous avez une liste Python dans le contexte appelé mylist :

{% for x in mylist | reverse %}
{% endfor %}

Processeurs de contexte

Pour injecter automatiquement de nouvelles variables dans le contexte d’un modèle, il existe des processeurs de contexte dans Flask. Les processeurs de contexte s’exécutent avant que le modèle ne soit rendu et ont la capacité d’injecter de nouvelles valeurs dans le contexte du modèle. Un processeur de contexte est une fonction qui renvoie un dictionnaire. Les clés et les valeurs de ce dictionnaire sont ensuite fusionnées avec le contexte du modèle, pour tous les modèles de l’application :

@app.context_processor
def inject_user():
    return dict(user=g.user)

Le processeur de contexte ci-dessus retourne une variable appelée user disponible dans le modèle avec la valeur de g.user. Cet exemple n’est pas très intéressant car g est disponible dans les modèles de toute façon, mais il donne une idée de comment cela fonctionne.

Les variables ne sont pas limitées aux valeurs ; un processeur de contexte peut également mettre des fonctions à la disposition des modèles (puisque Python permet de passer des fonctions en arguments) :

@app.context_processor
def utility_processor():
    def format_price(amount, currency="€"):
        return f"{amount:.2f}{currency}"
    return dict(format_price=format_price)

Le processeur de contexte ci-dessus retourne la fonction format_price disponible pour tous les modèles :

{{ format_price(0.33) }}

Vous pourriez aussi construire format_price comme un filtre de modèle (voir Enregistrement des filtres), mais ceci démontre comment passer des fonctions dans un processeur de contexte.