在Jinja2中,如何简单地将字典的所有键设置为其值?

2 投票
2 回答
6905 浏览
提问于 2025-04-16 01:57

我有一个仪表盘,它为每个仪表盘项目设置了命名空间。有没有什么简单的方法可以把字典里的所有值都设置到模板的键上?

我想重复使用模板,而不是每次都给我的变量加命名空间。

我的上下文可以简化成这样:

{
 "business": {"businesses": [], "new_promotions": []}, 
 "messages": {"one_to_one": [], "announcements": []
}

所以在一个 with 语句中,我想把所有的业务项目设置为局部变量,以便在包含的地方使用。目前,我必须一个一个地设置每个变量:

{% with %}
  {% set businesses = business["businesses"] %}
  {% set new_promotions = business["new_promotions"] %}
  {% include "businesses.html" %}
{% endwith %}

我试过:

{% with %}
  {% for key, value in my_dict %}
    {% set key = value %}
  {% endfor %}
  {% include "businesses.html" %}
{% endwith %}

但是它们只在 for 循环的范围内有效,所以在包含的地方就不行了...

2 个回答

1

我找到了一种解决办法——通过创建一个上下文函数,我可以渲染模板并直接设置上下文,或者把上下文合并在一起(不过我不太确定这样做是否是好习惯)。

@jinja2.contextfunction
def render(context, template_name, extra_context, merge=False):
    template = jinja_env.get_template(template_name)

    # Merge or standalone context?
    if merge:
        ctx = context.items()
        ctx.update(extra_context)
    else:
        ctx = extra_context

    return jinja2.Markup(template.render(ctx))

所以我的模板看起来是这样的:

{{ render("businesses.html", business) }}
4

简单来说,你不能在上下文中随便设置变量。{% set key = value %} 只是把名为 key 的变量设置为给定的值。

原因是 Jinja2 会把模板编译成 Python 代码。(如果你想看看你的模板生成了什么代码,可以下载这个脚本 http://ryshcate.leafstorm.us/paste/71c95831ca0f1d5,然后把你的模板文件名传给它。)为了加快处理速度,它会为模板中使用的每个变量创建局部变量(只在第一次遇到变量时查找上下文),而 Django 则是对所有变量查找都使用上下文。

为了正确生成这些代码,它需要能够跟踪在任何给定时刻存在哪些局部或全局变量,这样它才能知道什么时候去上下文中查找。而随便设置变量会让这个过程失效,这就是为什么 contextfunction 不允许修改上下文,只能查看它。

不过,我的建议是,不要把显示业务信息的代码放在一个包含的模板中,而是把它放在另一个模板的宏中。例如,在 businesses.html 中:

{% macro show_businesses(businesses, new_promotions) %}
  {# whatever you're displaying... #}
{% endmacro %}

然后在你的主模板中:

{% from "businesses.html" import show_businesses %}
{% show_businesses(**businesses) %}

或者,更好的是,把它们分成两个不同的宏——一个用于业务,一个用于新促销。你可以在 http://bitbucket.org/plurk/solace/src/tip/solace/templates/ 上看到很多有趣的模板技巧,当然也可以查看 Jinja2 的文档 http://jinja.pocoo.org/2/documentation/templates

撰写回答