2012-12-24 22 views
7

Ho una lista di namedtuples che sto passando, ognuno leggermente diverso nei requisiti di rendering, quindi voglio chiamare la macro corretta in base a un attributo. Quello che ho è questa:jinja2: macro selezione macro o chiamate macro dinamiche

{% macro format_item(item) %} 
    {% if item.type_of == 'a' %} 
     {{ format_a(item) }} 
    {% elif item.type_of == 'b' %} 
     {{ format_b(item) }} 
    {% elif item.type_of == 'c'%} 
     {{ format_c(item) }} 
    {% elif item.type_of == 'd'%} 
     {{ format_d(item) }} 
    {% else %} 
     {{ format_general(item) }} 
    {% endif %} 
{% endmacro %} 

ma quello che voglio è quello di qualcosa di simile:

...iterating through list of items 
{{ call macro based off item.type_of }} 

a questo punto in python regolare farei qualcosa come

getattr(object_with_method_to_produce_templates, item) 

ma rifugio 'Ho trovato un modo per usare efficacemente il filtro attr (se posso usarlo correttamente in questa situazione).

Ho trovato flask.get_template_attribute cercando altrove che potrebbe essere interessante (se posso invece farlo tutto in anticipo e inviare un elemento precalcolato e preformattato al modello). Forse troppo e al di là di quello che voglio fare in questo momento.

Qual è un modo migliore per chiamare da un elenco vario di macro invece di un elenco di se poi potrebbe diventare piuttosto grande in futuro? Sembra una domanda comune, ma non mi sono imbattuto nella risposta esatta che sto cercando.

EDIT:

ho aggiunto questo per quello che stavo facendo, cercando di generare una macro richiamabile come parte della voce che voglio rendere

from flask import get_template_attribute 
from jinja2 import Template 
test_template = Template('{% macro test_macro(item) %}<div id="test-div">sent to me: {{ item }}</div>{% endmacro %}') 

... in generazione elemento ...

template = get_template_attribute(test_template, 'test_macro') 

... in template ... iterare elementi poi per ogni elemento

{{ item.template("testing this method") }} 

che tipo di funziona ma genera solo la lettera di stringa per la lettera, non come una macro regolare (vale a dire. i div non sono resi come div, solo come testo).

<div id="test-div">sent to me: testing this method</div> 

quindi ho bisogno di dare Template qualche contesto, o qualcosa di questo è più vicino a quello che è stato mirando, ma non mi sembra giusto.

EDIT2:

{{ item.template("testing this method")|safe }} 

restituisce quello che cercavo, quindi questo è passabile, potrei essere in grado di bypassare la disposizione namedtuple ho avuto e solo passare una macro con ... più lavorare su di esso ho supporre. Questo è ottimale/preferibile o un disastro?

+0

Dai un'occhiata alla funzione di escape HTML nei documenti Jinja e al filtro sicuro. – voscausa

+0

Ok, li ho guardati ma non ho fatto la connessione esatta che ho bisogno di fare.Quello che penso di aver fatto è creare una macro come un blocco di codice, ma non contrassegnarla come html (come indicherebbe un'estensione di file), quindi la macro viene semplicemente ribattezzata come testo normale, hmmm cerchiamo di girarla per un po ' . – blueblank

risposta

5

È possibile creare un filtro Jinja2 che ottiene la macro dal contesto corrente e quindi valuta la macro. Il filtro è:

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

vedere la risposta completa here.