CherryPy con Cheetah como complemento + herramienta – páginas en blanco

CherryPy sigue devolviendo páginas en blanco o con los valores que devuelvo en los controladores. Reescribí una versión de django y jinja2 que funcionó, al parecer esta no, que es casi idéntica a la mencionada anteriormente.

Hice algunas impresiones en el bit de la herramienta que llena la solicitud. Cuerpo con html analizado, pero no lo emite cuando el pase se establece en el controlador. Si devuelvo un {‘usuario’: Verdadero} en el controlador que se muestra en forma de un simple “Usuario”.

Con algunos ejemplos en línea y el código de SickBeard, llegué a lo siguiente:

controlador:

class RootController(object): @cherrypy.expose @cherrypy.tools.render(template="page/home.html") def index(self): pass 

herramienta:

 class CheetahTool(cherrypy.Tool): def __init__(self): cherrypy.Tool.__init__(self, 'on_start_resource', self._render, priority=30) def _render(self, template=None, debug=False): if cherrypy.response.status > 399: return # retrieve the data returned by the handler data = cherrypy.response.body or {} template = cherrypy.engine.publish("lookup-template", template).pop() if template and isinstance(data, dict): for k,v in data: template.__setattr__(k, v) # dump the template using the dictionary if debug: try: cherrypy.response.body = unicode(template).encode('utf-8', 'xmlcharrefreplace') except Exception as e: from pprint import pprint pprint(e.message) else: cherrypy.response.body = template.respond() 

enchufar:

 class PageTemplate(Template): """ Thank you SickBeard """ def __init__(self, base_dir, template, *args, **KWs): KWs['file'] = os.path.join(base_dir, template) super(PageTemplate, self).__init__(*args, **KWs) application = cherrypy.tree.apps[''] config = application.config self.sbRoot = base_dir self.sbHttpPort = config['global']['server.socket_port'] self.sbHttpsPort = self.sbHttpPort self.sbHttpsEnabled = False if cherrypy.request.headers['Host'][0] == '[': self.sbHost = re.match("^\[.*\]", cherrypy.request.headers['Host'], re.X|re.M|re.S).group(0) else: self.sbHost = re.match("^[^:]+", cherrypy.request.headers['Host'], re.X|re.M|re.S).group(0) if "X-Forwarded-Host" in cherrypy.request.headers: self.sbHost = cherrypy.request.headers['X-Forwarded-Host'] if "X-Forwarded-Port" in cherrypy.request.headers: self.sbHttpPort = cherrypy.request.headers['X-Forwarded-Port'] self.sbHttpsPort = self.sbHttpPort if "X-Forwarded-Proto" in cherrypy.request.headers: self.sbHttpsEnabled = True if cherrypy.request.headers['X-Forwarded-Proto'] == 'https' else False self.sbPID = str(aquapi.PID) self.menu = [ { 'title': 'Home', 'key': 'home' }, { 'title': 'Users', 'key': 'users' }, { 'title': 'Config', 'key': 'config' }, ] def render(self): return unicode(self).encode('utf-8', 'xmlcharrefreplace') class CheetahTemplatePlugin(plugins.SimplePlugin): def __init__(self, bus, base_dir=None, base_cache_dir=None, collection_size=50, encoding='utf-8'): plugins.SimplePlugin.__init__(self, bus) self.base_dir = base_dir self.base_cache_dir = base_cache_dir or tempfile.gettempdir() self.encoding = encoding self.collection_size = collection_size def start(self): self.bus.log('Setting up Cheetah resources') self.bus.subscribe("lookup-template", self.get_template) def stop(self): self.bus.log('Freeing up Cheetah resources') self.bus.unsubscribe("lookup-template", self.get_template) self.lookup = None def get_template(self, name): """ Returns Cheetah's template by name. """ return PageTemplate(self.base_dir, name) 

en eso:

  # Template engine tool from aquapi.web.tools.template import CheetahTool cherrypy.tools.render = CheetahTool() # Tool to load the logged in user or redirect # the client to the login page from aquapi.web.tools.user import UserTool cherrypy.tools.user = UserTool() from aquapi.web.controllers import RootController webapp = RootController() # Let's mount the application so that CherryPy can serve it app = cherrypy.tree.mount(webapp, '/', os.path.join(self.base_dir, "app.cfg")) # Template engine plugin from aquapi.web.plugin.template import CheetahTemplatePlugin engine.cheetah = CheetahTemplatePlugin(engine, os.path.join(self.base_dir, 'aquapi/web/templates'), os.path.join(self.base_dir, 'cache')) engine.cheetah.subscribe() 

En general, para mí es una especie de ingeniería excesiva que se produjo en tus fragmentos. Los complementos de CherryPy se usan generalmente para una tarea del sistema (por ejemplo, poner el archivo PID en el arranque del motor, eliminarlo en la parada) o para una tarea asíncrona (por ejemplo, enviar un correo electrónico en un hilo separado). La representación de la plantilla se realiza de forma claramente sincrónica con el manejo de la solicitud, por lo que no veo el punto de extraer esta lógica de la herramienta CherryPy. Hay una clase en CherryPy, cherrypy._cptools.HandlerWrapperTool , que demuestra el enfoque sugerido para ajustar los valores de retorno del manejador.

Nunca he usado Cheetah, así que mi ejemplo está basado en Jinja2. Solo tendrá que cambiar la instancia del motor de plantillas (a Cheetah) y corregir sus llamadas. El rest es el mismo.

 #!/usr/bin/env python # -*- coding: utf-8 -*- import os import types import cherrypy import jinja2 path = os.path.abspath(os.path.dirname(__file__)) config = { 'global' : { 'server.socket_host' : '127.0.0.1', 'server.socket_port' : 8080, 'server.thread_pool' : 4 } } class TemplateTool(cherrypy.Tool): _engine = None '''Jinja environment instance''' def __init__(self): viewLoader = jinja2.FileSystemLoader(os.path.join(path, 'view')) self._engine = jinja2.Environment(loader = viewLoader) cherrypy.Tool.__init__(self, 'before_handler', self.render) def __call__(self, *args, **kwargs): if args and isinstance(args[0], (types.FunctionType, types.MethodType)): # @template args[0].exposed = True return cherrypy.Tool.__call__(self, **kwargs)(args[0]) else: # @template() def wrap(f): f.exposed = True return cherrypy.Tool.__call__(self, *args, **kwargs)(f) return wrap def render(self, name = None): cherrypy.request.config['template'] = name handler = cherrypy.serving.request.handler def wrap(*args, **kwargs): return self._render(handler, *args, **kwargs) cherrypy.serving.request.handler = wrap def _render(self, handler, *args, **kwargs): template = cherrypy.request.config['template'] if not template: parts = [] if hasattr(handler.callable, '__self__'): parts.append(handler.callable.__self__.__class__.__name__.lower()) if hasattr(handler.callable, '__name__'): parts.append(handler.callable.__name__.lower()) template = u'/'.join(parts) data = handler(*args, **kwargs) or {} renderer = self._engine.get_template(u'{0}.html'.format(template)) return renderer.render(**data) cherrypy.tools.template = TemplateTool() class App: @cherrypy.expose def index(self): '''No renderer applied, CherryPy outputs dict keys''' return {'user': 123} @cherrypy.tools.template def auto(self): return {'user': 123} @cherrypy.tools.template(name = 'app/auto') def manual(self): return {'user': 234} if __name__ == '__main__': cherrypy.quickstart(App(), '/', config) 

A lo largo del archivo python, cree la view/app directorio view/app y coloque lo siguiente en el archivo llamado auto.html allí.

     Test   

User: {{ user }}

Algunas notas en el TemplateTool . Primero, puede usarlo como decorador de dos maneras: no hacer una llamada y hacer una llamada con el argumento del nombre de la plantilla. Puede usar la herramienta como cualquier otra herramienta de CherryPy en la configuración (por ejemplo, hacer que todos los métodos de controlador generen plantillas). En segundo lugar, siguiendo el principio de convención sobre configuración, la herramienta, cuando no se proporciona con el nombre de la plantilla, usará classname/methodname.html . En tercer lugar, el decorador expone el método, por lo que no es necesario agregar @cherrypy.expose en la parte superior.