Reputation: 17926
I'm trying to do something like this:
{% macro obj_type_1 %}
stuff
{% endmacro %}
{% macro obj_type_2 %}
stuff
{% endmacro %}
{{ (obj|get_type)(obj) }}
In this example, get_type
is a filter that would return obj_type_1
or obj_type_2
-- ie, the name of the macro to call for obj
. I don't want to mark up obj
with configuration output because right now obj
is used in several templates as structural data, to be rendered with different markup depending on the context.
I know the syntax here is a bit tortured, but I think that's because what I want to do isn't immediately possible in Jinja templates. I'm trying to replace a big damn schwack of if/elif/else crap in some config generation code with templates, but this bit seems to be a sticking point.
Upvotes: 8
Views: 6781
Reputation: 7799
Macros can simply called by import dict usage:
macros.html
{% macro render_foo(value) %}
HELLO {{ value }}!
{% endmacro %}
my_view.html
{% import "macros.html" as my_macros %}
{% set macro_name = 'render_' + dynamic_content %}
{{ my_macros[macro_name]('world') }}
render as:
HELLO world!
Upvotes: 7
Reputation: 2626
You can create a Jinja2 filter which gets the Macro from the current context and then evaluates the Macro. The filter is:
@contextfilter
def call_macro_by_name(context, macro_name, *args, **kwargs):
return context.vars[macro_name](*args, **kwargs)
If your application requires, you can perform string manipulation on macro_name before looking up the Macro in context.vars.
Here is a full example:
#!/usr/bin/env python
from jinja2 import Environment, contextfilter
@contextfilter
def call_macro_by_name(context, macro_name, *args, **kwargs):
return context.vars[macro_name](*args, **kwargs)
template_string = """\
{%- macro MyMacro(item) %}MyMacro({{ item }}){% endmacro -%}
{{ MyMacro('direct') }}
{{ 'MyMacro' | macro('indirect') }}
"""
env = Environment()
env.filters['macro'] = call_macro_by_name
template = env.from_string(template_string)
print(template.render())
which prints
MyMacro(direct)
MyMacro(indirect)
Upvotes: 10
Reputation: 49886
Personally, since get_type is used as a dispatcher, it would be more transparent to implement it as a jinja macro that calls a specialized macro based on the type of obj. This removes the need for it to return a callable macro and, at the same time, consolidates the specialized macros and the logic that dictates how/when they are used.
Upvotes: 0