jinja2: выбор макроса макроса или вызовы динамических макросов

У меня есть список namedtuples, которые я просматриваю, каждый из которых немного отличается по требованиям к рендерингу, поэтому я хочу вызвать правильный макрос на основе атрибута. У меня есть это:

{% 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 %}

но я хочу что-то вроде:

...iterating through list of items
{{ call macro based off item.type_of }}

в этот момент в обычном питоне я бы сделал что-то вроде

getattr(object_with_method_to_produce_templates, item)

но не нашел способа эффективно использовать фильтр attr (если я вообще могу использовать его правильно в этой ситуации).

Я нашел flask.get_template_attribute в другом месте, что может быть интересно (если вместо этого я могу просто сделать все это заранее и отправить предварительно рассчитанный и предварительно отформатированный элемент в шаблон). Может быть, слишком много и сверх того, что я хочу сделать в это время.

Какой лучший способ вызова из разнообразного списка макросов вместо списка if then, который может стать довольно большим в будущем? Кажется, общий вопрос, но я не наткнулся на точный ответ, который я ищу.

РЕДАКТИРОВАТЬ:

Я добавил это к тому, что делал, пытаясь создать вызываемый макрос как часть элемента, который я хочу отобразить.

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 %}')

...в генерации предметов...

 template = get_template_attribute(test_template, 'test_macro')

... в шаблоне... повторять элементы, затем для каждого элемента

{{ item.template("testing this method") }}

какой вид работает, но только генерирует строковую букву для буквы, а не как обычный макрос (т.е. div не отображаются как div, только как текст).

<div id="test-div">sent to me: testing this method</div>

Поэтому мне нужно дать Template какой-то контекст или что-то, что ближе к тому, к чему я стремился, но кажется неправильным.

РЕДАКТИРОВАТЬ2:

{{ item.template("testing this method")|safe }}

возвращает то, что я искал, так что это приемлемо, я мог бы обойти имеющуюся у меня схему namedtuple и просто передать макрос с... дополнительной работой над ним, я полагаю. Это оптимально / предпочтительно или беспорядок?


person blueblank    schedule 24.12.2012    source источник
comment
Взгляните на экранирование HTML в документации Jinja и безопасный фильтр.   -  person voscausa    schedule 24.12.2012
comment
Хорошо, я просмотрел их, но не нашел точной связи, которую мне нужно установить. Я думаю, что создал макрос в виде блока кода, но не пометил его как html (на что указывает расширение файла), поэтому макрос просто преобразуется в обычный текст, хммм, давайте немного покопаемся в этом .   -  person blueblank    schedule 24.12.2012


Ответы (1)


Вы можете создать фильтр Jinja2, который получает макрос из текущего контекста, а затем оценивает макрос. Фильтр:

@contextfilter
def call_macro_by_name(context, macro_name, *args, **kwargs):
    return context.vars[macro_name](*args, **kwargs)

См. полный ответ здесь.

person Matt Liberty    schedule 03.07.2014