4

我的应用程序在 App Engine 上运行,并使用WerkzeugJinja2实现。我想要一些功能上等同于 Django 自己的上下文处理器的东西:一个可调用的,它接受一个请求并将一些东西添加到模板上下文中。我已经有一个“上下文处理器”,可以在模板上下文中添加一些内容,但是如何让这个请求部分工作?我将上下文处理器实现为一个可调用对象,它只返回一个稍后用于更新上下文的字典。

例如,我想添加一些包含在request.environ.

4

2 回答 2

4

实现这一点的一种方法是通过使用Werkzeug 中的线程本地代理的后期绑定模板全局变量。

将请求放入模板全局变量的简单示例:

from werkzeug import Local, LocalManager
local = Local()
local_manager = LocalManager([local])

from jinja2 import Environment, FileSystemLoader

# Create a global dict using the local's proxy to the request attribute
global_dict = {'request': local('request')}
jinja2_env = Environment(loader=FileSystemLoader('/'))
jinja2_env.globals.update(global_dict)

def application(environ, start_response):
    """A WSGI Application"""
    # later, bind the actual attribute to the local object
    local.request = request = Request(environ)

    # continue to view handling code
    # ...

application = local_manager.make_middleware(application)

现在在您的任何模板中,当前请求将显示为绑定到变量“request”。当然,这可能是周围的任何其他东西。诀窍是使用本地代理,然后在渲染任何模板之前设置值。

我可能还应该补充一点,像Glashammer (Werkzeug+Jinja2) 这样的框架通过使用事件为您简化了这个过程。许多函数可以在 WSGI 调用过程中连接到事件(例如,当创建请求时),它们可以在此时将内容放入模板命名空间中。

于 2009-02-11T23:55:13.297 回答
3

好吧,使用Ali 写的内容,我找到了特定于 App Engine 的解决方案(因为它的导入缓存)。不幸的是,Ali 的代码不适用于 App Engine,因为设置 Jinja 全局变量的代码只导入一次(使全局变量实际上是静态的)。

我必须编写自己的render()函数并在那里更新上下文。为了完整起见,下面是我来的代码:

def render(template, **kwargs):
    response_code = kwargs.pop('response_code', 200)
    mimetype = kwargs.pop('mimetype', 'text/html')
    for item in getattr(settings, 'CONTEXT_PROCESSORS', []):
        try:
            processor = import_string(item)
            kwargs.update(processor(local.request))
        except (ImportError, AttributeError), e:
            logging.error(e)
    return Response(jinja_env.get_template(template).render(**kwargs),
        status=response_code, mimetype=mimetype)

这是 App Engine 特定的。在其他环境中,阿里的代码按预期工作(这就是我重新标记我的问题的原因)。

于 2009-02-18T21:02:52.687 回答