2011-05-17 21 views
99

Estoy usando jinja2, y quiero llamar a una función de python como un ayudante, usando una sintaxis similar como si estuviera llamando a una macro. jinja2 parece decidido a evitar que haga una llamada a función e insiste en que me repita copiando la función en una plantilla como una macro.Llamar a una función de pitón desde jinja2

¿Hay alguna manera directa de hacer esto? Y, ¿hay alguna manera 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)?

Respuesta

61

Creo que jinja deliberadamente hace que sea difícil ejecutar python 'arbitrario' dentro de una plantilla. Intenta forzar 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 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 
+3

descubrí esto también - se puede añadir un módulo usando algo como esto: 'utils.helpers importación env.globals [ 'ayudantes'] = utils.helpers' – Lee

+0

@Lee. Sí, puede 'inyectar' espacios de nombres (módulos), funciones, instancias de clases, etc. Es útil, pero no tan flexible como otros motores de plantillas como el mako. Aún así, jinja tiene otros buenos puntos. Le agradecería si aceptara la respuesta si ayuda :) –

+0

me funcionó mientras hacía mi proyecto de motor de aplicación (webapp2 y jinja2). gracias –

175

Para aquellos que utilizan el frasco, puso esto en su __init__.py:

def clever_function(): 
    return u'HELLO' 

app.jinja_env.globals.update(clever_function=clever_function) 

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

+0

puede pasar múltiples funciones como esta? – ffghfgh

+0

En las versiones más nuevas (estoy usando Jinja2 2.9.6) parece funcionar mucho más fácil. Utilice la función de igual modo que una variable (también funciona en situaciones más complejas): ' a partir de plantilla de importación Jinja2 ## de nueva línea ## clever_function def(): ## de nueva línea ## retorno "Hola" nueva línea ## ## template = plantilla ("{{clever_function()}}") ## ## nueva línea de impresión (template.render (clever_function = clever_function)) ' –

83

Nota: Esto es específico frasco!

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

Las variables pueden ser fácilmente creados:

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

Lo anterior puede ser utilizado en una plantilla Jinja2 con el frasco así:

{{ myexample }} 

(que emite This is an example)

Además de las funciones completas:

@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 de esta manera:

{{ format_price(0.33) }} 

(que emite el precio de entrada con el símbolo de moneda)

Como alternativa, puede utilizar jinja filters, al horno en el frasco. P.ej.utilizando decoradores:

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

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

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

filtros aplicados con los dos métodos anteriores se pueden utilizar como esto:

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

donde debería existir estas funciones, init, vistas o simplemente ¿en cualquier sitio? – knk

+3

'__init __. Py' suponiendo que ha declarado' flask.Flask (__ nombre __) 'allí. –

+5

Abajo vota como una pregunta acerca de Jinja2 y la respuesta es específica para el Frasco. – AJP

6

Uso 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 a la perfección en la plantilla

{{clever_function(value)}} 
+0

Uso inteligente de las funciones lambda. – odiumediae

+12

@odiumediae: No, no lo es. Es completamente innecesario. Solo pase el identificador de la función en sí: función_flexible = función_funda – vezult

+0

@vezult Ya veo. ¿Cómo podría extrañar eso? Gracias por aclarar eso! – odiumediae

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

seria:

Hey, my name is Jay 

funciona con la versión 2.7.3 Jinja2

+0

¿Por qué el voto a favor? – AJP

+7

Probablemente porque bajaste las respuestas de todos los demás :( –

+9

@BorkoKovacev eso no es una buena razón. Solo voté 2 respuestas, las cuales fueron sobre Flask en lugar de Jinja2.Si quieren editar sus respuestas para estar en el tema y sobre Jinja2 voy a votar por ellos. – AJP

3

Para llamar a una función de Python 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 myTemplate.txt archivo, escribí:

{{ data|pythonFct }} 

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

Si usted lo está haciendo con Django, sólo puede pasar a la función con el contexto:

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

Ahora usted será capaz de utilizar la función str en la plantilla Jinja2

5

nunca vio de manera sencilla en documentos oficiales o al desbordamiento de pila, pero me quedé sorprendido cuando se encuentra presente:

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

¿hay alguna manera de importar todo un conjunto de funciones de Python y les tienen acceso desde Jinja2?

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

Crear una clase y rellenarla con los métodos asociados, por ejemplo,

class Test_jinja_object: 

    def __init__(self): 
     self.myvar = 'sample_var' 

    def clever_function (self): 
     return 'hello' 

A continuación, crear una instancia de la clase en su función de vista y pasar el objeto resultante a la plantilla como un parámetro para la función de render_template

my_obj = Test_jinja_object() 

en su plantilla, puede llamar a los métodos de la clase en Jinja al igual que

{{ my_obj.clever_function() }} 
4

Me gusta @AJP's answer. Lo usé textualmente hasta que terminé con muchas funciones. Luego cambié a Python function decorator.

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__!

0

Para importar todas las funciones incorporadas que puede utilizar:

app.jinja_env.globals.update(__builtins__) 

Añadir .__dict__ después __builtins__ si esto no funciona.

Basado en John32323's answer.

Cuestiones relacionadas