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

发布于 2024-07-13 08:39:42 字数 397 浏览 4 评论 0原文

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

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

My application is running on App Engine and is implemented using Werkzeug and Jinja2. I'd like to have something functionally equivalent of Django's own context processor: a callable that takes a request and adds something to the template context. I already have a "context processors" that add something to the template context, but how do I get this request part working? I implemented context processors as a callables that just return a dictionary that later is used to update context.

For example, I'd like to add something that is contained in request.environ.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凯凯我们等你回来 2024-07-20 08:39:42

实现此目的的一种方法是通过后期绑定 模板全局变量在 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 调用过程中(例如,创建请求时)连接到事件,并且此时它们可以将内容放入模板命名空间中。

One way of achieving this is through late-bound template globals using the thread-local proxy in Werkzeug.

A simple example that puts the request into the the template globals:

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)

Now in any of your templates, the current request will appear bound to the variable "request". Of course that could be anything else in environ. The trick is to use the local proxy, then set the value before you render any template.

I should probably also add that a framework like Glashammer (Werkzeug+Jinja2) streamlines this process for you by using events. Many functions can connect to the events during the process of the WSGI call (for example, when a request is created) and they can put stuff in the template namespace at that point.

月朦胧 2024-07-20 08:39:42

好吧,使用阿里写的我得出了解决方案特定于 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 特定的。 在其他环境中,阿里的代码按预期工作(这就是我重新标记我的问题的原因)。

Well, using what Ali wrote I came to the solution that is specific to App Engine (because of its import cache). Unfortunately, Ali's code does not work with App Engine, because the code that sets Jinja globals are imported only once (making the globals effectively static).

I had to write my own render() function and update the context there. For completeness sake, below is the code I came to:

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)

This is App Engine specific. In other environments Ali's code works as expected (and that's why I am retagging my question).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文