CherryPy与猎豹作为插件+工具 - 空白页 [英] CherryPy with Cheetah as plugin + tool - blank pages

查看:212
本文介绍了CherryPy与猎豹作为插件+工具 - 空白页的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

CherryPy不断返回空白页面或返回控制器中的值。我重写了一个django和jinja2版本,这显然是不是与前面提到的几乎相同。

CherryPy keeps returning blank pages or with the values I return in the controllers. I rewrote a django and jinja2 version that did work, apparently this one doesn't which is almost identical to the previous mentioned.

我在工具中做了一些pprint使用解析的html填充request.body,但是在控制器中设置pass时不输出。如果我在控制器中返回一个{user:True},以简单的用户的形式显示。

I did some pprint's in the tool bit which does fill the request.body with parsed html but doesn't output it when pass is set in the controller. If I return a {'user':True} in the controller that is shown in the form of a simple "User".

在线和代码的SickBeard我来到以下:

with a few examples online and the code of SickBeard I came to the following:

控制器:

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

工具:

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

插件:

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)

init :

        # 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()


推荐答案

一般来说,对我而言,这是一种过度工程发生在你的片段中。 CherryPy插件通常用于系统任务(例如,将PID文件放在引擎启动,停止时将其删除)或异步任务(例如,以单独的线程发送电子邮件)。模板渲染与请求处理同步清楚,所以我没有看到从CherryPy工具中提取出这个逻辑。 CherryPy中有一个课程, cherrypy._cptools.HandlerWrapperTool ,它展示了包装处理程序返回值的建议方法。

In general, to me it's some sort of over-engineering happened in your snippets. CherryPy plugins are usually used for a system task (e.g. put PID-file on engine start, remove it on stop) or for an asynchronous task (e.g. sending email in separate thread). Template rendering happens clearly synchronously to the request handling, so I don't see the point of extracting this logic out of CherryPy tool. There's a class in CherryPy, cherrypy._cptools.HandlerWrapperTool, which demonstrate the suggested approach to wrapping handler return values.

我没有使用过猎豹,所以我的例子是基于Jinja2的。您只需要更改模板引擎实例(到Cheetah)并更正其调用。其余的是相同的。

I haven't ever used Cheetah, so my example is Jinja2-based. You will just have to change the templating engine instance (to Cheetah) and correct its calls. The rest is the same.

#!/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)

沿着python文件创建目录 view / app ,并将以下内容放入文件名 auto.html 那里。

Along the python file, create directory view/app and put the following in file named auto.html there.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv='content-type' content='text/html; charset=utf-8' />
    <title>Test</title>
  </head>
  <body>
    <p>User: <em>{{ user }}</em></p>
  </body>
</html>

有关 TemplateTool 的注释。首先,您可以通过两种方式将其用作装饰器:不进行调用,并使用模板名称参数进行调用。您可以使用该工具作为配置中的任何其他CherryPy工具(例如,使所有控制器方法呈现模板)。其次,按照惯例配置原则,没有提供模板名称的工具将使用 classname / methodname.html 。第三,装饰器公开了这个方法,所以你不需要在顶部添加 @ cherrypy.expose

Some notes on the TemplateTool. First, you can use it as a decorator in two ways: not making a call, and making a call with template name argument. You can use the tool as any other CherryPy tool in the configuration (e.g. make all controller methods to render templates). Second, following convention-over-configuration principle, the tool when not provided with template name will use classname/methodname.html. Third, the decorator exposes the method, so you don't need to add @cherrypy.expose on top.

这篇关于CherryPy与猎豹作为插件+工具 - 空白页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆