问题
I've got a dashboard that namespaces the context for each dashboard item. Is there a quick way I can set all the values of a dictionary to the keys in a template?
I want to reuse templates and not always namespace my variables.
My context can be simplified to look something like this:
{
"business": {"businesses": [], "new_promotions": []},
"messages": {"one_to_one": [], "announcements": []
}
So in a with statement I want to set all the business items to be local for the including. To do this currently I have to set each variable individually:
{% with %}
{% set businesses = business["businesses"] %}
{% set new_promotions = business["new_promotions"] %}
{% include "businesses.html" %}
{% endwith %}
I tried:
{% with %}
{% for key, value in my_dict %}
{% set key = value %}
{% endfor %}
{% include "businesses.html" %}
{% endwith %}
But they only have scope in the for loop so aren't scoped in the include...
回答1:
Long story short: you can't set arbitrary variables in the context. The {% set key = value %}
is just setting the variable named key
to the given value.
The reason is because Jinja2 compiles templates down to Python code. (If you want to see the code your template generates, download the script at http://ryshcate.leafstorm.us/paste/71c95831ca0f1d5 and pass it your template's filename.) In order to make processing faster, it creates local variables for every variable you use in the template (only looking up the variable in the context the first time it's encountered), as opposed to Django, which uses the context for all variable lookups.
In order to generate this code properly, it needs to be able to track which local or global variables exist at any given time, so it knows when to look up in the context. And setting random variables would prevent this from working, which is why contextfunction
s are not allowed to modify the context, just view it.
What I would do, though, is instead of having your business-displaying code be an included template, is have it be a macro in another template. For example, in businesses.html
:
{% macro show_businesses(businesses, new_promotions) %}
{# whatever you're displaying... #}
{% endmacro %}
And then in your main template:
{% from "businesses.html" import show_businesses %}
{% show_businesses(**businesses) %}
Or, better yet, separate them into two separate macros - one for businesses, and one for new promotions. You can see a lot of cool template tricks at http://bitbucket.org/plurk/solace/src/tip/solace/templates/, and of course check the Jinja2 documentation at http://jinja.pocoo.org/2/documentation/templates.
回答2:
I've found a work around - by creating a context function I can render the template and directly set the context or merge the context (not sure thats good practise though).
@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))
So my templates look like:
{{ render("businesses.html", business) }}
来源:https://stackoverflow.com/questions/3352724/in-jinja2-whats-the-easiest-way-to-set-all-the-keys-to-be-the-values-of-a-dictio