2011-12-22 25 views
8

Estoy usando plantillas Jinja2 con Bottle.py y dev_appserver de Google App Engine para el desarrollo. Quiero que las plantillas se vuelvan a cargar automáticamente en cada solicitud (o idealmente solo cuando cambien), para que no tenga que seguir reiniciando el servidor.¿Cuál es la mejor manera de desactivar el almacenamiento en caché de plantillas Jinja2 en bottle.py?

De acuerdo con los documentos de la botella, se supone que debe poder deshabilitar el almacenamiento en caché de plantillas llamando al bottle.debug(True).

Sin embargo, Jinja parece estar almacenando sus plantillas en caché. Creo que esto se debe a la forma en que está escrito el adaptador jinja2 de la botella (solo usa un cargador Jinja2 predeterminado y no expone muchas opciones de configuración).

Tras la Jinja2 Docs, he escrito este cargador personalizado que yo esperaría para desencadenar una plantilla cada vez que vuelva a cargar, pero no parece funcionar bien:

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 
    } 
) 

plantillas todavía se están guardados hasta que reinicie dev_appserver. Este debe ser un problema bastante común. ¿Alguien tiene una solución que funciona?

ACTUALIZACIÓN:

que terminé haciendo algo como:

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) 

Esto hace que las plantillas para recargar siempre, pero sólo si un módulo de Python ha sido tocado. es decir, si solo edita un archivo de plantilla, los cambios no tendrán efecto hasta que edite uno de los archivos de Python que lo importa. Parece que las plantillas todavía se almacenan en caché en algún lugar.

Respuesta

6

Resolví este problema abandonando completamente las soluciones de plantilla de botella y usando jinja2 puro. Parece que el FileSystemLoader de Jijnja es el único que puede ver los cambios de archivos.

he definido nueva función template de la siguiente manera (busca los archivos en views/, al igual que la botella se utiliza para):

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) 

Entonces utilizar de esta manera:

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

La diferencia de El API de la botella es que debe incluir .tpl en el nombre del archivo y debe pasar variables de contexto como diccionario.

3

El objeto Environment en Jinja2 tiene un valor de configuración para el tamaño de la caché y, de acuerdo a la documentación,

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

Ha intentado algo como esto?

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

Usar la vista de la botella decorador, sólo puede hacer @view('your_view', cache_size=0).

La botella tiene un parámetro reloader=True en el adaptador del servidor, pero supongo que funciona solo con SimpleTemplate. Trataré de extender este comportamiento a otros motores de plantillas.

Si desea hacerlo en todos sus puntos de vista, tal vez usted puede hacer algo como esto:

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

De esta manera, usted puede hacerlo sólo cuando esté en modo de depuración añadiendo una sentencia if para este código if bottle.DEBUG.

+0

Downarrowing porque el argumento cache_size = 0 no me funcionaba usando el decorador view() o la función template(). También ejecutar (reloader = True) arroja un error: "variable local 'lockfile' referenciado antes de la asignación" – arkanciscan

+0

@arkanciscan este error probablemente no está relacionado con mi respuestaq, pero está bien. Solo para su conocimiento, informé de su comentario como un problema para embotellar (https://github.com/defnull/bottle/issues/278). ¿Puedes dar más detalles sobre el error en github? ¿Qué adaptador de servidor estás usando? ¡Gracias! – iurisilvio

+0

+1 para el informe de error, gracias :) – defnull

5

Plantillas de caché de botella internamente (independientes del almacenamiento en caché Jinja2). Puede desactivar el caché a través del bottle.debug(True) o bottle.run(..., debug=True) o borrar el caché con bottle.TEMPLATES.clear().

+0

Gracias por la respuesta. No sabía sobre bottle.TEMPLATES.clear(), que podría ser útil. He tenido bottle.debug (True) establecido desde el comienzo del proyecto, así que estoy bastante seguro de que ha sido un problema configurar la memoria caché de Jinja. – leted

+0

Lo que me ha molestado es ejecutar bottle.debug (True) antes de bottle.run. El argumento de depuración de bottle.run tiene un valor predeterminado de False que sobrescribe bottle.DEBUG si no se especifica. –

Cuestiones relacionadas