1

我通过 mod_wsgi 用 Apache 设置了 Python 3.2。我有 CherryPy 3.2 提供一个简单的“Hello World”网页。在构建网站时,我想开始使用 Jinja2 进行模板化。我是 Python 新手,因此对 Python、CherryPy 或 Jinja 了解不多。

使用下面的代码,我可以加载站点根目录 ( /) 和产品页面 ( /products) 及其基本文本。这至少让我知道我已经正确设置了 Python、mod_wsgi 和 CherryPy。

因为该站点将有很多页面,所以我想以一种无需在每个页面处理程序类中声明和呈现模板的方式来实现 Jinja 模板。据我所知,最好的方法是包装 PageHandler,类似于以下示例:

我已经实现了第二个示例中的代码,但它并没有改变任何东西。

[代码后的更多细节]

wsgi_handler.py -一些教程和示例的混搭

import sys, os
abspath = os.path.dirname(__file__)
sys.path.append(abspath)
sys.path.append(abspath + '/libs')
sys.path.append(abspath + '/app')
sys.stdout = sys.stderr

import atexit
import threading
import cherrypy
from cherrypy._cptools import HandlerWrapperTool
from libs.jinja2 import Environment, PackageLoader

# Import from custom module
from core import Page, Products

cherrypy.config.update({'environment': 'embedded'})

env = Environment(loader=PackageLoader('app', 'templates'))

# This should wrap the PageHandler
def interpolator(next_handler, *args, **kwargs):
    template = env.get_template('base.html')
    response_dict = next_handler(*args, **kwargs)
    return template.render(**response_dict)

# Put the wrapper in place(?)
cherrypy.tools.jinja = HandlerWrapperTool(interpolator)

# Configure site routing
root = Page()
root.products = Products()

# Load the application
application = cherrypy.Application(root, '', abspath + '/app/config')

/应用程序/配置

[/]
request.dispatch: cherrypy.dispatch.MethodDispatcher()

核心模块类

class Page:
    exposed = True

    def GET(self):
        return "got Page"

    def POST(self, name, password):
        return "created"

class Products:
    exposed = True

    def GET(self):
        return "got Products"

    def POST(self, name, password):
        return "created"

根据我在Google Group上阅读的内容,我认为我可能需要“打开”Jinja 工具,因此我将配置更新为:

/应用程序/配置

[/]
tools.jinja.on = True
request.dispatch: cherrypy.dispatch.MethodDispatcher()

更新配置后,站点根目录和产品页面显示 CherryPy 生成的错误页面“500 Internal Server Error”。在日志中没有找到详细的错误消息(至少在我知道的日志中没有)。

除非它是预先安装的,否则我知道我可能需要那里的Jinja 工具,但我不知道把它放在哪里或如何启用它。我怎么做?

我是以正确的方式解决这个问题,还是有更好的方法?

编辑(2012 年 5 月 21 日):

这是我正在使用的 Jinja2 模板:

<!DOCTYPE html>
<html>
    <head>
        <title>{{ title }}</title>
    </head>
    <body>
        <h1>Hello World</h1>
    </body>
</html>
4

2 回答 2

1

我想到了。

interpolator函数中,next_handler函数调用原来的PageHandler(Page.GETProducts.GET在本例中)。那些原始的 PageHandlers 返回字符串,而interpolator函数将响应视为 python dict(字典),因此当它传递给template.renderas时会出现双星号**response_dict

Jinja 模板有一个 的占位符title,因此需要定义一个标题。将纯字符串传递给渲染函数并没有定义标题应该是什么。我们需要将一个实际的 dict 传递给 render 函数(或者什么都不传递,但这有什么好处呢?)。

注意:对于这些修复中的任何一个,都需要启用 jinja 工具,如问题所示,tools.jinja.on在配置中设置为 True。

快速解决

在调用渲染函数时定义标题。为此,我需要更改此行:

return template.render(**response_dict) # passing the string as dict - bad

对此:

return template.render(title=response_dict) # pass as string and assign to title

像这样,模板以我的 PageHandler 文本作为页面标题呈现。

更好的修复

因为模板会变得更加复杂,所以一个渲染函数可能并不总是能够正确分配必要的占位符。让原始页面处理程序返回一个实际的 dict 并分配模板的许多占位符可能是一个好主意。

保持插值器函数不变:

def interpolator(next_handler, *args, **kwargs):
    template = env.get_template('base.html')
    response_dict = next_handler(*args, **kwargs)
    return template.render(**response_dict)

更新 Page 和 Products 以返回为模板的占位符定义值的实际字典:

class Page:
    exposed = True

    def GET(self):
        dict = {'title' : "got Page"}
        return dict

    def POST(self, name, password):
        # This should be updated too
        # I just haven't used it yet
        return "created"

class Products:
    exposed = True

    def GET(self):
        dict = {'title' : "got Products"}
        return dict

    def POST(self, name, password):
        # This should be updated too
        # I just haven't used it yet
        return "created"

像这样,模板以我的 PageHandler 标题文本作为页面标题呈现。

于 2012-05-21T17:17:16.173 回答
1

在社区贡献的各种配方的存储库中还可以找到一个更新的Jinja2工具。

于 2012-05-22T19:50:55.887 回答