我的应用程序在App Engine上运行,并使用Werkzeug和Jinja2实现。我想在功能上等同于Django自己的上下文处理器:一个可调用的请求并向模板上下文添加一些东西。我已经有一个“上下文处理器”,它可以为模板上下文添加一些内容,但是如何让这个请求部分工作?我将上下文处理器实现为一个callable,只返回一个字典,后来用于更新上下文。
例如,我想添加request.environ
中包含的内容。
答案 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特有的。在其他环境中,阿里的代码按预期工作(这就是我重新提出问题的原因)。