J'utilise jinja2 et je souhaite appeler une fonction python comme aide, en utilisant une syntaxe similaire à celle utilisée pour appeler une macro. jinja2 semble vouloir m'empêcher de faire un appel de fonction et insiste pour que je me répète en copiant la fonction dans un modèle sous forme de macro.
Y at-il un moyen simple de faire cela? Et est-il possible d'importer tout un ensemble de fonctions python et de les rendre accessibles à partir de jinja2, sans passer par beaucoup de rigamarole (comme écrire une extension)?
Pour ceux qui utilisent Flask, mettez ceci dans votre __init__.py
:
def clever_function():
return u'HELLO'
app.jinja_env.globals.update(clever_function=clever_function)
et dans votre modèle, appelez-le avec {{ clever_function() }}
Note: Ceci est spécifique à Flask!
Je sais que ce message est assez ancien, mais il existe de meilleures méthodes pour le faire dans les nouvelles versions de Flask utilisant des processeurs de contexte.
Les variables peuvent être facilement créées:
@app.context_processor
def example():
return dict(myexample='This is an example')
Ce qui précède peut être utilisé dans un modèle Jinja2 avec Flask comme ceci:
{{ myexample }}
(Quelles sorties This is an example
)
Ainsi que des fonctions à part entière:
@app.context_processor
def utility_processor():
def format_price(amount, currency=u'€'):
return u'{0:.2f}{1}'.format(amount, currency)
return dict(format_price=format_price)
Le ci-dessus lorsqu'il est utilisé comme suit:
{{ format_price(0.33) }}
(Qui affiche le prix d'entrée avec le symbole monétaire)
Vous pouvez également utiliser jinja filters , cuit dans Flask. Par exemple. en utilisant des décorateurs:
@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]
Ou, sans décorateurs, et en enregistrant manuellement la fonction:
def reverse_filter(s):
return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter
Les filtres appliqués avec les deux méthodes ci-dessus peuvent être utilisés comme ceci:
{% for x in mylist | reverse %}
{% endfor %}
Je pense que jinja rend délibérément difficile la gestion de python "arbitraire" dans un modèle. Il essaie de renforcer l’opinion selon laquelle moins de logique dans les modèles est une bonne chose.
Vous pouvez manipuler l'espace de noms global au sein d'une instance Environment
pour ajouter des références à vos fonctions. Cela doit être fait avant vous chargez des modèles. Par exemple:
from jinja2 import Environment, FileSystemLoader
def clever_function(a, b):
return u''.join([b, a])
env = Environment(loader=FileSystemLoader('/path/to/templates'))
env.globals['clever_function'] = clever_function
from jinja2 import Template
def custom_function(a):
return a.replace('o', 'ay')
template = 'Hey, my name is {{ custom_function(first_name) }}'
jinga_html_template = Template(template)
jinga_html_template.globals['custom_function'] = custom_function
fields = {'first_name': 'Jo'}
print jinga_html_template.render(**fields)
Est-ce que la sortie:
Hey, my name is Jay
Fonctionne avec Jinja2 version 2.7.3
Utilisez un lambda pour connecter le modèle à votre code principal
return render_template("clever_template", clever_function=lambda x: clever_function x)
Ensuite, vous pouvez appeler de manière transparente la fonction dans le modèle
{{clever_function(value)}}
Je n'ai jamais vu un moyen aussi simple dans les documents officiels ou au débordement de pile, mais j'ai été étonné de constater ceci:
# jinja2.__version__ == 2.8
from jinja2 import Template
def calcName(n, i):
return ' '.join([n] * i)
template = Template("Hello {{ calcName('Gandalf', 2) }}")
template.render(calcName=calcName)
# or
template.render({'calcName': calcName})
J'aime la réponse de @ AJP . Je l'ai utilisé textuellement jusqu'à ce que je termine avec beaucoup de fonctions. Puis je suis passé à un décorateur de fonctions Python .
from jinja2 import Template
template = '''
Hi, my name is {{ custom_function1(first_name) }}
My name is {{ custom_function2(first_name) }}
My name is {{ custom_function3(first_name) }}
'''
jinga_html_template = Template(template)
def template_function(func):
jinga_html_template.globals[func.__name__] = func
return func
@template_function
def custom_function1(a):
return a.replace('o', 'ay')
@template_function
def custom_function2(a):
return a.replace('o', 'ill')
@template_function
def custom_function3(a):
return 'Slim Shady'
fields = {'first_name': 'Jo'}
print(jinga_html_template.render(**fields))
Les bonnes choses ont un __name__
!
Pour appeler une fonction python depuis Jinja2, vous pouvez utiliser des filtres personnalisés qui fonctionnent de la même façon que les globals: http://jinja.pocoo.org/docs/dev/api/#writing-filters
C'est assez simple et utile . Dans un fichier myTemplate.txt, j'ai écrit:
{{ data|pythonFct }}
Et dans un script python:
import jinja2
def pythonFct(data):
return "This is my data: {0}".format(data)
input="my custom filter works!"
loader = jinja2.FileSystemLoader(path or './')
env = jinja2.Environment(loader=loader)
env.filters['pythonFct'] = pythonFct
result = env.get_template("myTemplate.txt").render(data=input)
print(result)
est-il possible d'importer tout un ensemble de fonctions python et de les avoir accessibles à partir de jinja2?
Oui, en plus des autres réponses ci-dessus, cela fonctionne pour moi.
Créez une classe et remplissez-la avec les méthodes associées, par exemple
class Test_jinja_object:
def __init__(self):
self.myvar = 'sample_var'
def clever_function (self):
return 'hello'
Créez ensuite une instance de votre classe dans votre fonction de vue et transmettez l'objet résultant à votre modèle en tant que paramètre pour la fonction render_template
my_obj = Test_jinja_object()
Maintenant, dans votre modèle, vous pouvez appeler les méthodes de classe en jinja comme
{{ my_obj.clever_function () }}
Pour importer toutes les fonctions intégrées, vous pouvez utiliser:
app.jinja_env.globals.update(__builtins__)
Ajoutez .__dict__
après __builtins__
si cela ne fonctionne pas.
Basé sur la réponse de John32323 .
Si vous le faites avec Django, vous pouvez simplement passer la fonction avec le contexte:
context = {
'title':'My title',
'str': str,
}
...
return render(request, 'index.html', context)
Vous pourrez maintenant utiliser la fonction str
dans le modèle jinja2