使用Werkzeug和Jinja2的上下文处理器

时间:2009-02-11 22:22:40

标签: python django google-app-engine jinja2 werkzeug

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

例如,我想添加request.environ中包含的内容。

2 个答案:

答案 0 :(得分:4)

实现这一目标的一种方法是使用Werkzeug中的template globals进行后期thread-local proxy

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

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调用过程中连接到事件(例如,创建请求时),并且可以在此时将内容放入模板命名空间中。

答案 1 :(得分:3)

好吧,使用what Ali wrote我找到了特定于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特有的。在其他环境中,阿里的代码按预期工作(这就是我重新提出问题的原因)。