Llama a una función python desde jinja2

Estoy usando jinja2, y quiero llamar a una función de python como ayudante, usando una syntax similar como si estuviera llamando a una macro. jinja2 parece tener la intención de evitar que realice una llamada de función e insiste en que me repito copiando la función en una plantilla como una macro.

¿Hay alguna forma sencilla de hacer esto? Y, ¿hay alguna forma de importar un conjunto completo de funciones de Python y tenerlas accesibles desde jinja2, sin pasar por un montón de rigamarole (como escribir una extensión)?

Para aquellos que usan Flask, ponga esto en su __init__.py :

 def clever_function(): return u'HELLO' app.jinja_env.globals.update(clever_function=clever_function) 

y en su plantilla {{ clever_function() }} con {{ clever_function() }}

Nota: ¡Esto es específico del matraz!

Sé que esta publicación es bastante antigua, pero hay mejores métodos para hacerlo en las versiones más recientes de Flask utilizando procesadores de contexto.

Las variables se pueden crear fácilmente:

 @app.context_processor def example(): return dict(myexample='This is an example') 

Lo anterior se puede utilizar en una plantilla de Jinja2 con Frasco como:

 {{ myexample }} 

(Qué salidas This is an example )

Así como funciones completas de pleno derecho:

 @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) 

Lo anterior cuando se usa como tal:

 {{ format_price(0.33) }} 

(Que genera el precio de entrada con el símbolo de moneda)

Alternativamente, puedes usar filtros jinja , horneados en Flask. Por ejemplo, usando decoradores:

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

O, sin decoradores, y registrando manualmente la función:

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

Los filtros aplicados con los dos métodos anteriores se pueden utilizar así:

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

Creo que jinja deliberadamente hace que sea difícil ejecutar python ‘arbitrario’ dentro de una plantilla. Intenta imponer la opinión de que menos lógica en las plantillas es algo bueno.

Puede manipular el espacio de nombres global dentro de una instancia de Environment para agregar referencias a sus funciones. Debe hacerse antes de cargar cualquier plantilla. Por ejemplo:

 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 = Template('Hey, my name is {{ custom_function(first_name) }} {{ func2(last_name) }}') template.globals['custom_function'] = custom_function 

También puede dar la función en los campos según la respuesta de Matroskin.

 fields = {'first_name': 'Jo', 'last_name': 'Ko', 'func2': custom_function} print template.render(**fields) 

Saldrá:

 Hey, my name is Jay Kay 

Funciona con la versión 2.7.3 de Jinja2.

Y si desea que un decorador facilite la definición de las funciones en template.globals consulte la respuesta de Bruno Bronosky

Nunca vi una manera tan simple en los documentos oficiales o en el desbordamiento de stack, pero me sorprendió cuando encontré esto:

 # 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}) 

Me gusta la respuesta de @AJP . Lo usé textualmente hasta que terminé con muchas funciones. Luego me cambié a un decorador de función 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)) 

Las funciones buenas tienen un __name__ !

Use una lambda para conectar la plantilla a su código principal

 return render_template("clever_template", clever_function=lambda x: clever_function x) 

A continuación, puede llamar a la función en la plantilla sin problemas

 {{clever_function(value)}} 

Para llamar a una función python desde Jinja2, puede usar filtros personalizados que funcionan de manera similar a los globales: http://jinja.pocoo.org/docs/dev/api/#writing-filters

Es bastante simple y útil. En un archivo myTemplate.txt, escribí:

 {{ data|pythonFct }} 

Y en un script de 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) 

¿Hay alguna manera de importar un conjunto completo de funciones de python y tenerlas accesibles desde jinja2?

Sí, hay, además de las otras respuestas anteriores, esto funciona para mí.

Cree una clase y rellénela con los métodos asociados, por ejemplo,

 class Test_jinja_object: def __init__(self): self.myvar = 'sample_var' def clever_function (self): return 'hello' 

Luego cree una instancia de su clase en su función de vista y pase el objeto resultante a su plantilla como un parámetro para la función render_template

 my_obj = Test_jinja_object() 

Ahora en tu plantilla, puedes llamar a los métodos de clase en jinja así

 {{ my_obj.clever_function () }} 

Para importar todas las funciones incorporadas puedes usar:

 app.jinja_env.globals.update(__builtins__) 

Agregue .__dict__ después de __builtins__ si esto no funciona.

Basado en la respuesta de John32323 .

Si lo haces con Django, puedes pasar la función con el contexto:

 context = { 'title':'My title', 'str': str, } ... return render(request, 'index.html', context) 

Ahora podrás usar la función str en la plantilla jinja2