在Jinja2中,如何简单地将字典的所有键设置为其值?
我有一个仪表盘,它为每个仪表盘项目设置了命名空间。有没有什么简单的方法可以把字典里的所有值都设置到模板的键上?
我想重复使用模板,而不是每次都给我的变量加命名空间。
我的上下文可以简化成这样:
{
"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 个回答
我找到了一种解决办法——通过创建一个上下文函数,我可以渲染模板并直接设置上下文,或者把上下文合并在一起(不过我不太确定这样做是否是好习惯)。
@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) }}
简单来说,你不能在上下文中随便设置变量。{% 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。