2012-05-17 20 views
7

que estoy tratando de hacer algo como esto:¿Cómo puedo llamar indirectamente una macro en una plantilla Jinja2?

{% macro obj_type_1 %} 
stuff 
{% endmacro %} 
{% macro obj_type_2 %} 
stuff 
{% endmacro %} 

{{ (obj|get_type)(obj) }} 

En este ejemplo, get_type es un filtro que devolvería obj_type_1 o obj_type_2 - es decir, el nombre de la macro para pedir obj. No quiero marcar obj con salida de configuración porque ahora obj se usa en varias plantillas como datos estructurales, para representar con diferentes marcas dependiendo del contexto.

Sé que la sintaxis aquí es un poco torturada, pero creo que es porque lo que quiero hacer no es inmediatamente posible en las plantillas de Jinja. Estoy tratando de reemplazar una gran mierda de if/elif/else en algún código de generación de config con plantillas, pero este bit parece ser un punto de fricción.

+0

Así Básicamente, se está buscando una manera de 'eval()' en Jinja2? – Blender

+0

Cerca de; Quiero llamar a una macro por nombre. –

Respuesta

0

Personalmente, dado que get_type se utiliza como despachador, sería más transparente implementarlo como una macro jinja que llama a una macro especializada en función del tipo de obj. Esto elimina la necesidad de devolver una macro invocable y, al mismo tiempo, consolida las macros especializadas y la lógica que dicta cómo y cuándo se usan.

8

Puede crear un filtro Jinja2 que obtenga la macro del contexto actual y luego evalúe la macro. El filtro es:

@contextfilter 
def call_macro_by_name(context, macro_name, *args, **kwargs): 
    return context.vars[macro_name](*args, **kwargs) 

Si su aplicación requiere, puede realizar la manipulación de cadenas en nombre_macro antes de levantar la macro en context.vars.

Aquí es un ejemplo completo:

#!/usr/bin/env python 
from jinja2 import Environment, contextfilter 

@contextfilter 
def call_macro_by_name(context, macro_name, *args, **kwargs): 
    return context.vars[macro_name](*args, **kwargs) 

template_string = """\ 
{%- macro MyMacro(item) %}MyMacro({{ item }}){% endmacro -%} 
{{ MyMacro('direct') }} 
{{ 'MyMacro' | macro('indirect') }} 
""" 

env = Environment() 
env.filters['macro'] = call_macro_by_name 
template = env.from_string(template_string) 
print(template.render()) 

que imprime

MyMacro(direct) 
MyMacro(indirect) 
2

macros pueden simplemente llamado por el uso dict importación:

macros.html

{% macro render_foo(value) %} 
HELLO {{ value }}! 
{% endmacro %} 

my_view.html

{% import "macros.html" as my_macros %} 

{% set macro_name = 'render_' + dynamic_content %} 
{{ my_macros[macro_name]('world') }} 

rendir como:

HELLO world! 
Cuestiones relacionadas