Попытка сформировать веб-страницу на основе шаблона Jinja2. пустой файл на выходе
Есть задача формирования веб-страницы на основе списка. Для теста накидал код. На выходе получаю пустой файл. Что делаю не так?
test.py
from jinja2 import Environment, FileSystemLoader
environment = Environment(loader=FileSystemLoader("templates/"))
results_filename = "test-jinja-result.html"
results_template = environment.get_template("test-jinja.html")
test_title = "Test Jinja2 template"
files_name = [
{"filenameindir": "1_files", "flie_number": 1},
{"filenameindir": "2_files", "flie_number": 2},
{"filenameindir": "8_files", "flie_number": 5},
{"filenameindir": "2_files", "flie_number": 7},
{"filenameindir": "3_files", "flie_number": 3},
{"filenameindir": "4_files", "flie_number": 4},
]
context = {
"filenameindir": files_name,
"test-title": test_title,
}
with open(results_filename, mode="w", encoding="utf-8") as results:
results.write(results_template.render(context))
print(f"... wrote {results_filename}")
test-jinja.html
{# templates/test-jinja.html #}
<body>
<h1>{{ test_title }}</h1>
<ul>
{% for file in files_name %}
<li><em> {{ files_name.filenameindir }} </em></li>
{% endfor %}
</ul>
</body>
Добавлю информации. Ошибок в коде не выдает. Файл результата выглядит так:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Results</title>
</head>
<body>
<h1></h1>
<ul>
</ul>
</body>
</html>
Вот содержимое Conext через дебаг:
Ответы (1 шт):
Сначала совет, чтобы проще было отлавливать проблемы при работе с jinja, нужно добавить параметр undefined=StrictUndefined
при создании Environment
:
from jinja2 import Environment, FileSystemLoader, StrictUndefined
environment = Environment(loader=FileSystemLoader("templates/"), undefined=StrictUndefined)
Тогда jinja будет падать при рендеринге, если какую-то переменную в контексте не найдет. На коде из вопроса будет так:
...
File "templates/test-jinja.html", line 4, in top-level template code
<h1>{{ test_title }}</h1>
jinja2.exceptions.UndefinedError: 'test_title' is undefined
Т.е. не нашло test_title
- потому что в контексте у вас test-title
, а не test_title
.
Первая проблема — у вас не совпадают ключи в контексте, и имена в шаблоне, по которым вы данные из контекста пытаетесь получить. Ключи в контексте и имена в шаблоне должны в точности совпадать.
Если вы записали данные в контекст по ключу filenameindir
, а пытаетесь в шаблоне вытащить files_name
- это не сработает, у вас в контексте нет никакого files_name
. Нужно сделать, чтобы ключи в контексте и запрашиваемые имена в шаблоне совпадали.
Сами имена должны быть через подчеркивание, а не через дефис, как вы в контексте test-title
сделали. Если оставить в контексте test-title
, и поменять на такое же имя в шаблоне, jinja воспримет это как арифметическую операцию test - title
, и будет ругаться, что нет имени test
. Поэтому в именах используйте подчеркивания.
Пример правильного контекста (под ваш шаблон):
context = {
"files_name": files_name,
"test_title": test_title,
}
Важны именно ключи — то что слева от двоеточия, а не имена переменных, в которых значения лежали раньше. Имена переменных вообще никак не сохраняются в словаре (контексте), соответственно jinja про них не сможет узнать.
Данные по ключам могут добавляться из переменных с другими именами, главное, чтобы ключи словаря-контекста и имена в шаблоне совпадали.
Вторая проблема: в цикле в шаблоне вы берете данные не из элементов списка files_name
, а из самого списка files_name
.
Чтобы бралось из элементов списка файлов, нужно обращаться к переменной file
:
<ul>
{% for file in files_name %} {# file - переменная, в которую попадают данные файла #}
<li><em> {{ file.filenameindir }} </em></li> {# и из этой же переменной file получаем filenameindir #}
{% endfor %}
</ul>
Полный исправленный код:
from jinja2 import Environment, FileSystemLoader, StrictUndefined
environment = Environment(loader=FileSystemLoader("templates/"), undefined=StrictUndefined)
results_filename = "test-jinja-result.html"
results_template = environment.get_template("test-jinja.html")
test_title = "Test Jinja2 template"
files_name = [
{"filenameindir": "1_files", "flie_number": 1},
{"filenameindir": "2_files", "flie_number": 2},
{"filenameindir": "8_files", "flie_number": 5},
{"filenameindir": "2_files", "flie_number": 7},
{"filenameindir": "3_files", "flie_number": 3},
{"filenameindir": "4_files", "flie_number": 4},
]
context = {
"files_name": files_name,
"test_title": test_title,
}
with open(results_filename, mode="w", encoding="utf-8") as results:
results.write(results_template.render(context))
print(f"... wrote {results_filename}")
Шаблон:
{# templates/test-jinja.html #}
<body>
<h1>{{ test_title }}</h1>
<ul>
{% for file in files_name %}
<li><em> {{ file.filenameindir }} </em></li>
{% endfor %}
</ul>
</body>
Готовый файл:
<body>
<h1>Test Jinja2 template</h1>
<ul>
<li><em> 1_files </em></li>
<li><em> 2_files </em></li>
<li><em> 8_files </em></li>
<li><em> 2_files </em></li>
<li><em> 3_files </em></li>
<li><em> 4_files </em></li>
</ul>
</body>
Чтобы пустые строки не добавлялись, можно добавить черточку после % в операторах начала и конца цикла:
<ul>
{%- for file in files_name %}
<li><em> {{ file.filenameindir }} </em></li>
{%- endfor %}
</ul>
Выходной файл:
<body>
<h1>Test Jinja2 template</h1>
<ul>
<li><em> 1_files </em></li>
<li><em> 2_files </em></li>
<li><em> 8_files </em></li>
<li><em> 2_files </em></li>
<li><em> 3_files </em></li>
<li><em> 4_files </em></li>
</ul>
</body>