2012-01-14 11 views
5

Supponiamo di avere un codice template jinja effettivo in una variabile X. Diciamo che il contenuto di X è "{{some_other_variable}}".Rendering nidificato Jinja sul contenuto variabile

Come posso visualizzare X durante il rendering del suo contenuto?

esempio, questo non funziona:

{{X}}

Come rende semplicemente questa maschera "{{some_other_variable}}" piuttosto che il contenuto di some_other_variable.

La ragione per cui sto facendo in questo modo è che ho un sito in cui gli utenti (fidati) possono creare post che possono contenere codice del template jinja. La pagina di visualizzazione mostra questi post, ma a causa del problema sopra riportato, li rende direttamente, piuttosto che sostituire le variabili come vorrei.

+0

Aggiunto spiegazione sopra – muckabout

risposta

2

non riuscivo a trovare un buon modo per fare questo rendering nidificato, però, posso provare a suggerire un alternative:

in quanto l'utente di creare i posti, immagino "{{}} some_other_variable" è in realtà sottostringa di tutto il post, che è anche una stringa.

vorrei fare:

X.replace("{{some_other_variable}}", some_other_variable)) 

poi tornare {{X}} come al solito. Questo soddisferà ciò che vorresti fare?

+0

sostituire Jinja2 sarebbe meglio th un questo. '{{X | replace (" {{Hello}} "," Arrivederci ")}}' Ho bisogno di più soluzioni native. –

+0

Non sono certamente il ragazzo più esperto là fuori. Sarei felice di sapere se c'è qualche ragione particolare per sostituire jinja2 meglio. Inoltre, cosa intendi per "nativo"? Come più vicino a Jinja2 possibile? – nglinh

+0

oh si, intendo decisamente il più vicino a Jinja2 possibile. Sto solo aspettando una soluzione più generica con la quale potrei aggiungere intere capacità jinja2 (non solo sostituzione di variabili) in questi scenari. Altrimenti, offrirei una taglia alla sostituzione variabile. Il filtro –

2

ho pensato di un modo interessante per fare questo:

  • Configurare un dizionario
  • Avvolgere una DictLoader intorno ad esso (ma mantenere un riferimento al dizionario intorno)
  • passare un chainloader con la DictLoader e il vostro normale Loader per l'ambiente
  • implementare un filtro personalizzato che aggiunge i suoi parametri per il dizionario di cui sopra
  • utilizzare la direttiva include per c tutto il codice template nel contesto attuale

Non ho provato, ma potrebbe funzionare!

+0

può fare qualsiasi cosa, non hai nemmeno bisogno dei passaggi da 1 a 3. puoi passare le variabili attraverso jinja. C'è qualcos'altro che gestirà la sostituzione delle variabili attraverso jinja, non solo manuale come questo. –

+0

Eh? Il filtro passa semplicemente i contenuti del modello e li inserisce nel dizionario del modello in modo che Jinja possa elaborarli nel solito modo. La parte difficile è ottenere il contesto di Jinja (in modo che tu possa usarlo per elaborare il modello). Inoltre, perché non vuoi usare un filtro personalizzato? – djc

2

Lo so che è un ritardo :) po 'ma ecco una soluzione senza impattare codice del modello:

import jinja2 
def recursive_render(tpl, values): 
    prev = tpl 
    while True: 
     curr = jinja2.Template(prev).render(**values) 
     if curr != prev: 
      prev = curr 
     else: 
      return curr 

Prova di funzionamento:

>>> recursive_render("Hello {{X}}!", dict(X="{{name}}", name="world")) 
u'Hello world!' 

Nota che questo non è molto efficiente, dal momento che il modello deve essere riascoltato da zero ad ogni iterazione.

0

Questo è ciò che mi si avvicinò con, utilizzando l'opzione finalize per l'Ambiente:

def render (tpl, args): 
    scope = {} 
    scope['env'] = jinja2.Environment (finalize=lambda x: scope['env'].from_string (x).render (**args) if isinstance(x, str) and '{{' in x else x) 
    scope['env'].filters['q'] = lambda value: re.sub (r'"', r'\\"', value) 
    return scope['env'].from_string (tpl).render (**args) 

E 'un po' brutto, quindi i miglioramenti benvenuti :)

ma lo fa il rendering ricorsiva come l'OP stava chiedendo, e non si ferma fino a quando non c'è più {{ nell'output ..

sessione Esempio

>>> import jinja2 
>>> def render (tpl, args): 
...   scope = {} 
...   scope['env'] = jinja2.Environment (finalize=lambda x: scope['env'].from_string (x).render (**args) if isinstance(x, str) and '{{' in x else x) 
...   scope['env'].filters['q'] = lambda value: re.sub (r'"', r'\\"', value) 
...   return scope['env'].from_string (tpl).render (**args) 
... 
>>> render("this {{ outer_var }} wokring!", {"outer_var":"{{ inner_var }}", "inner_var":"{{ final_step }}", "final_step":"is"}) 
u'this is wokring!' 

EDIT:

Ok, refactoring il mio render funzione un po ', funzionalmente lo stesso, ma un po' più ordinato:

def render (tpl, args): 
    @jinja2.environmentfunction 
    def finalize (env, value): 
     if isinstance(value, (str, unicode)) and '{{' in value: 
      return env.from_string (value).render (args) 
     return value 
    env = jinja2.Environment (finalize=finalize) 
    env.filters['q'] = lambda value: re.sub (r'"', r'\\"', value) 
    return env.from_string (tpl).render (args) 
0

Ho trovato un modo di lavorare con i file di modello e gli ambienti globali.

def render(template, values): 
    prev = template.render(**values) 
    while True: 
     curr = Template(prev).render(siteinfo=config, menus=menus, blended_header=header, authors=authors, buildinfo=buildinfo, **values) 
     if curr != prev: 
      prev = curr 
     else: 
      return curr 

In questa versione, è necessario passare le variabili globali di ambiente alla funzione di rendering interno di questa funzione, e la funzione è di per sé deve essere nella funzione build.

Il modo per inviare contenuti ad essa è: render(template, dict(content=post, tags=tags))

dove template = env.get_template('index.html')

0

Crea nuovo filtro:

from jinja2 import contextfilter, Markup 

@contextfilter 
def subrender_filter(context, value): 
    _template = context.eval_ctx.environment.from_string(value) 
    result = _template.render(**context) 
    if context.eval_ctx.autoescape: 
     result = Markup(result) 
    return result 

env = Environment() 
env.filters['subrender'] = subrender_filter 

E poi utilizzarlo in modello:

{{ "Hello, {{name}}"|subrender }} 
Problemi correlati