I have a list of namedtuples I'm going through, each slightly differing in rendering requirements, so I want to call the proper macro based on an attribute. What I have is this:
{% macro format_item(item) %}
{% if item.type_of == 'a' %}
{{ format_a(item) }}
{% elif item.type_of == 'b' %}
{{ format_b(item) }}
{% elif item.type_of == 'c'%}
{{ format_c(item) }}
{% elif item.type_of == 'd'%}
{{ format_d(item) }}
{% else %}
{{ format_general(item) }}
{% endif %}
{% endmacro %}
but what I want is to something like:
...iterating through list of items
{{ call macro based off item.type_of }}
at this point in regular python I'd do something like
getattr(object_with_method_to_produce_templates, item)
but haven't figured out a way to use the attr filter effectively (if I can use it properly in this situation at all).
I've found flask.get_template_attribute looking elsewhere which might be interesting (if I can instead just do it all ahead of time and send a precalculated and preformatted item to the template). Maybe too much and beyond what I want to do at this time.
What is a better way to call from a varied listing of macros instead of a list of if then's that might get rather large in the future? Seems like a common question, but I have not stumbled on the exact answer I'm looking for.
EDIT:
I added this to what I was doing, trying to generate a callable macro as part of the item I want to render
from flask import get_template_attribute
from jinja2 import Template
test_template = Template('{% macro test_macro(item) %}<div id="test-div">sent to me: {{ item }}</div>{% endmacro %}')
...in item generation...
template = get_template_attribute(test_template, 'test_macro')
...in template...iterate items then for each item
{{ item.template("testing this method") }}
which sort of works but only generates the string letter for letter, not as a regular macro would(i.e. the divs aren't rendered as divs, only as text).
<div id="test-div">sent to me: testing this method</div>
So I need to give Template some context, or something this is closer to what was aiming for but doesn't seem right.
EDIT2:
{{ item.template("testing this method")|safe }}
returns what I was looking for, so this is passable, I might be able to bypass the namedtuple arrangement I had and just pass a macro with...more working on it I suppose. Is this optimal/preferable or a mess though?
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)
See the full answer here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With