2011-12-22 8 views
8

Uso i modelli Jinja2 con Bottle.py e dev_appserver di Google App Engine per lo sviluppo. Voglio che i modelli si ricarichino automaticamente su ogni richiesta (o idealmente solo quando cambiano), in modo che non debba continuare a riavviare il server.Qual è il modo migliore per disattivare il caching del modello Jinja2 in bottle.py?

In base ai documenti del flacone, si suppone che si possa disabilitare il caching del modello chiamando lo bottle.debug(True).

Jinja sembra ancora che memorizzi i suoi modelli nella cache. Credo che ciò sia dovuto al modo in cui viene scritto l'adattatore jinja2 per bottiglia (utilizza solo un caricatore Jinja2 predefinito e non espone molte opzioni di configurazione).

Dopo la Jinja2 Docs, ho scritto questo Loader personalizzato che mi aspetterei per innescare un modello di ricaricare ogni volta, ma non sembra funzionare sia:

import settings 
from bottle import jinja2_template 
from bottle import Jinja2Template, template as base_template 
class AutoreloadJinja2Template(Jinja2Template): 
    def loader(self, name): 
     def uptodate(): 
      # Always reload the template if we're in DEVMODE (a boolean flag) 
      return not settings.DEVMODE 
     fname = self.search(name, self.lookup) 
     if fname: 
      with open(fname, "rb") as f: 
       source = f.read().decode(self.encoding) 
      return (source, fname, uptodate) 


template = functools.partial(base_template, 
    template_adapter=AutoreloadJinja2Template, 
    template_lookup = settings.TEMPLATE_PATHS, 
    template_settings={ 
     'auto_reload': settings.DEVMODE 
    } 
) 

I modelli sono ancora sempre memorizzati nella cache fino a quando ho riavviare dev_appserver. Questo deve essere un problema abbastanza comune. Qualcuno ha una soluzione che funziona?

UPDATE:

ho finito per fare qualcosa di simile:

class CustomJinja2Template(Jinja2Template): 
    if settings.DEVMODE: 
     def prepare(self, *args, **kwargs): 
      kwargs.update({'cache_size':0}) 
      return Jinja2Template.prepare(self, *args, **kwargs) 

template = functools.partial(original_template, template_adapter=CustomJinja2Template) 

Questo fa sì che i modelli di ricaricare sempre, ma solo se un modulo Python è stato toccato. Ad esempio, se si modifica un file modello, le modifiche non avranno effetto finché non si modifica uno dei file Python che lo importa. Sembra che i modelli siano ancora memorizzati nella cache da qualche parte.

risposta

6

Ho risolto questo problema eliminando completamente le soluzioni di modello delle bottiglie e utilizzando puro jinja2. Sembra che l'FileSystemLoader di Jijnja sia l'unico in grado di controllare le modifiche ai file.

ho definito nuova funzione template come segue (sembra per i file in views/, proprio come la bottiglia usata per):

from jinja2 import Environment, FileSystemLoader 

if local_settings.DEBUG: 
    jinja2_env = Environment(loader=FileSystemLoader('views/'), cache_size=0) 
else: 
    jinja2_env = Environment(loader=FileSystemLoader('views/')) 

def template(name, ctx): 
    t = jinja2_env.get_template(name) 
    return t.render(**ctx) 

allora io uso in questo modo:

@route('/hello') 
def hello(): 
    return template('index.tpl', {'text': "hello"}) 

La differenza da L'API di bottle è che devi includere .tpl nel nome del file e devi passare le variabili di contesto come dizionario.

3

Il Environment oggetto in Jinja2 ha un valore di configurazione per la dimensione della cache e, secondo la documentazione,

If the cache size is set to 0 templates are recompiled all the time

Hai provato qualcosa di simile?

from jinja2 import Environment 
env = Environment(cache_size=0) 
1

Utilizzando decoratore di bottiglie, basta fare @view('your_view', cache_size=0).

La bottiglia ha un parametro reloader=True nell'adattatore del server, ma suppongo che funzioni solo con SimpleTemplate. Proverò ad estendere questo comportamento ad altri motori di template.

Se si vuole fare in tutti i vostri punti di vista, forse si può fare qualcosa di simile:

import functools 
view = functools.partials(view, cache_size=0) 

In questo modo, si può fare solo quando si è in modalità di debug aggiungendo un'istruzione if a questo codice if bottle.DEBUG.

+0

Downarrowing perché l'argomento cache_size = 0 non ha funzionato con me utilizzando la funzione view() decorator o template(). Esegui anche (reloader = True) genera un errore: "variabile locale 'lockfile' referenziato prima dell'assegnazione" – arkanciscan

+0

@arkanciscan questo errore probabilmente non è correlato al mio responseq, ma va bene. Solo per tua conoscenza, ho segnalato il tuo commento come un problema da imbottigliare (https://github.com/defnull/bottle/issues/278). Puoi fornire maggiori dettagli sul bug in github? Quale adattatore server stai usando? Grazie! – iurisilvio

+0

+1 per il bug report, grazie :) – defnull

5

Modelli di cache cache internamente (indipendenti dalla cache Jinja2). È possibile disabilitare la cache tramite bottle.debug(True) o bottle.run(..., debug=True) o cancellare la cache con bottle.TEMPLATES.clear().

+0

Grazie per la risposta. Non sapevo di bottle.TEMPLATES.clear(), che potrebbe tornare utile! Ho avuto bottle.debug (True) set dall'inizio del progetto, quindi sono abbastanza sicuro che è stato un problema configurare il cache di Jinja. – leted

+0

Quello che mi ha bloccato è eseguire bottle.debug (True) prima di bottle.run. L'argomento debug di bottle.run ha un valore predefinito di False che sovrascrive bottle.DEBUG se non specificato. –