Jinja-шаблонизация с рекурсией в словаре не работает.

Вопрос или проблема

Вот мой небольшой скрипт на Python:

path = Path(__file__).parent

env = Environment(
    loader=FileSystemLoader(path / "templates")
)
template = env.get_template("template1.rst")

rendered = template.render(sample={"a": {"b": "c"}})

А вот мой шаблон для Jinja:


.. toctree::
   :maxdepth: 3

{% for k, v in sample.items() recursive %}
- {{ k }}:

  {%- if v is string %}
    {{ v }}

  {%- else %}
    {{ loop(v) }}
  
  {%- endif -%}

{%endfor%}

Терминал выдает мне следующую ошибку:

File "/home/jaja/Bureau/coding/bac_a_sable/sphinx_test/templates/template1.rst", line 5, in top-level template code
    {% for k, v in sample.items() recursive %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jaja/Bureau/coding/bac_a_sable/sphinx_test/templates/template1.rst", line 21, in template
    {{ loop(v) }}
^^^^^^^^^^^^^^^^^^
  File "/home/jaja/Bureau/coding/bac_a_sable/sphinx_test/templates/template1.rst", line 5, in template
    {% for k, v in sample.items() recursive %}
    ^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: not enough values to unpack (expected 2, got 1)

Так как значение v в первом цикле равно {“b”: “c”}, это должно работать, но не работает.
Не может ли Jinja рекурсивно обрабатывать словари?

Ответ или решение

Проблема, с которой вы столкнулись, касается рекурсивного обхода словаря с использованием шаблонов Jinja2. Давайте разберем ваш код и ошибки, чтобы выявить, как мы можем это исправить.

Анализ исходного кода

Ваш скрипт Python выглядит так:

path = Path(__file__).parent

env = Environment(
    loader=FileSystemLoader(path / "templates")
)
template = env.get_template("template1.rst")

rendered = template.render(sample={"a": {"b": "c"}})

Вы загружаете шаблон template1.rst и передаете в него словарь sample со следующей структурой: {"a": {"b": "c"}}. Теперь давайте разберемся с шаблоном Jinja:

.. toctree::
   :maxdepth: 3

{% for k, v in sample.items() recursive %}
- {{ k }}:

  {%- if v is string %}
    {{ v }}

  {%- else %}
    {{ loop(v) }}

  {%- endif -%}

{%endfor%}

Проблема с рекурсивной итерацией

Ошибка, которую вы получаете (ValueError: not enough values to unpack (expected 2, got 1)), указывает на то, что Jinja не может корректно обработать ваш цикл for с использованием ключевого слова recursive. Распаковывая значения из sample.items(), шаблон ожидает два значения (ключ и значение), но когда значение является вложенным словарем, возникает ошибка.

Решение проблемы

Вместо использования loop(v) в вашем шаблоне, необходимо провести новый цикл по вложенному словарю v. Мы можем использовать тот же подход, применив еще один уровень циклов for, что позволит вам обрабатывать вложенные значения. Вот как может выглядеть исправленный шаблон:

.. toctree::
   :maxdepth: 3

{% macro render_dict(d) %}
{% for k, v in d.items() %}
- {{ k }}:

  {%- if v is string %}
    {{ v }}
  {%- else %}
    {{ render_dict(v) }}
  {%- endif %}
{% endfor %}
{% endmacro %}

{{ render_dict(sample) }}

Объяснение внесенных изменений

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

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

  3. Упрощение вывода: Конструкция ${{ render_dict(sample) }} позволяет нам начать процесс рендеринга, передавая исходный словарь sample в наш макрос.

Заключение

Убедитесь, что вы включаете обработку вложенных структур в шаблоне Jinja, используя макросы, что позволяет избежать ошибок, связанных с попыткой рекурсивного обхода простым циклом for. Применяя этот подход, вы сможете эффективно обрабатывать любое количество вложенных словарей и избежать возникающих ошибок. Если у вас есть дальнейшие вопросы, не стесняйтесь обращаться.

Оцените материал
Добавить комментарий

Капча загружается...