我的应用程序在 App Engine 上运行,并使用Werkzeug和Jinja2实现。我想要一些功能上等同于 Django 自己的上下文处理器的东西:一个可调用的,它接受一个请求并将一些东西添加到模板上下文中。我已经有一个“上下文处理器”,可以在模板上下文中添加一些内容,但是如何让这个请求部分工作?我将上下文处理器实现为一个可调用对象,它只返回一个稍后用于更新上下文的字典。
例如,我想添加一些包含在request.environ
.
实现这一点的一种方法是通过使用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 调用过程中连接到事件(例如,当创建请求时),它们可以在此时将内容放入模板命名空间中。
好吧,使用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 特定的。在其他环境中,阿里的代码按预期工作(这就是我重新标记我的问题的原因)。