2014-06-19 13 views
9

Mi piacerebbe avere un filtro personalizzato in Jinja2 come questo:lambda come argomento del filtro jinja2?

{{ my_list|my_real_map_filter(lambda i: i.something.else)|some_other_filter }} 

Ma quando ho attuarlo, ottengo questo errore:

TemplateSyntaxError: expected token ',', got 'i' 

Appare la sintassi di Jinja2 non consente lambda come argomenti? C'è un bel trucco? Per ora, sto creando il lambda in python e poi lo passiamo al template come variabile, ma preferirei essere in grado di crearlo nel template.

+0

Per favore, non usare mai la logica complessa nei modelli. Non sono progettati per questo. Dovresti considerare come modelli leggeri il più possibile con la maggior parte delle operazioni logiche sul back-end. Immagina cosa diresti dopo aver trovato qualcosa di simile dopo un altro sviluppatore? Considera [buildin filters] (http://jinja.pocoo.org/docs/templates/#builtin-filters). 'Lambda' crea una funzione anonima che è molto più difficile da eseguire il debug. – boldnik

+1

Puoi suggerire un modo per fare ciò che voglio usando i filtri integrati? (cioè ho una lista di oggetti e ho bisogno di accedere a un attributo di un figlio di ciascuno degli oggetti?) Non penso che quello che sto cercando di fare sia davvero più complicato in senso logico di quello che è stato costruito in "mappa" lo consente, ma non penso di poter fare ciò che voglio con la mappa integrata. Per favore, mostrami se posso! – Lee

+0

La domanda è "lambda come argomento del filtro jinja2?" E la risposta è "No, non è possibile passare un'espressione generale Python per filtrare nel modello Jinja2". Sembra essere corretto Ora, se si desidera utilizzare un filtro personalizzato su un elenco di oggetti nel modello, la domanda è "perché".Perché non filtrare gli oggetti * prima * passando l'elenco al modello? Perché è necessario filtrare * dopo * passarlo al modello? – boldnik

risposta

6

No, non può passare l'espressione Python generale per filtrare in Jinja2 modello

La confusione deriva da modelli Jinja2 essere simile a sintassi Python in molti aspetti, ma si deve prendere come codice con la sintassi completamente indipendente.

Jinja2 ha regole rigide, cosa ci si può aspettare da quale parte del modello e in genere non consente il codice Python così com'è, si aspettano tipi esatti di espressioni, che sono piuttosto limitate.

Questo è in linea con il concetto, che la presentazione e il modello devono essere separati, quindi il modello non deve consentire troppa logica. In ogni caso, confrontando a molte altre opzioni di template, Jinja2 è abbastanza permissibile e consente un sacco di logica nei template.

6

Ho una soluzione, sto ordinamento di un oggetto dict:

registers = dict(
    CMD = dict(
     address = 0x00020, 
     name = 'command register'), 
    SR = dict(
     address = 0x00010, 
     name = 'status register'), 
) 

ho voluto un loop all'interno di dict registro, ma ordina per indirizzo. Quindi avevo bisogno di un modo per ordinare dal campo 'indirizzo'. Per fare questo, ho creato un filtro personalizzato e passare l'espressione lambda come una stringa, allora io uso eval built-in di Python() per creare il vero lambda:

def my_dictsort(value, by='key', reverse = False): 

    if by == 'key': 
     sort_by = lambda x: x[0].lower() # assumes key is a str 

    elif by == 'value': 
     sort_by = lambda x: x[1] 

    else: 
     sort_by = eval(by) # assumes lambda string, you should error check 

    return sorted(value, key = sort_by, reverse = reverse) 

Con questa funzione, è possibile iniettare nel Jinja2 ambiente in questo modo:

env = jinja2.Environment(...) 
env.filters['my_dictsort'] = my_dictsort 
env.globals['lookup'] = lookup   # queries a database, returns dict 

E poi chiamare dal tuo modello:

{% for key, value in lookup('registers') | my_dict_sort("lambda x:x[1]['address']") %} 
{{"""\ 
    static const unsigned int ADDR_{key} = 0x0{address:04X}; // {name} 
""" | format(key = key, address = value['address'], name = value['name']) 
}} 
{% endfor %} 

uscita:

static const unsigned int ADDR_SR = 0x00010; // status register 
static const unsigned int ADDR_CMD = 0x00020; // command register 

Quindi puoi passare una lambda come stringa, ma dovrai aggiungere un filtro personalizzato per farlo.

+0

Soluzione piacevole, ma un aspetto che potrebbe valere la pena considerare è la leggibilità del modello. Se l'output di un template può essere facilmente discerniciato dalla sola lettura dei filtri e dei comandi in esso contenuti, questa è una buona euristica per un design efficace. – dreftymac

Problemi correlati