3.4 Использование шаблонов Jinja и форм в FastAPI
6 из 6 шагов пройдено
1 из 1 баллa  получен

Использование шаблонов Jinja в FastAPI

Для начала нам нужно установить пакет Jinja.

pip install jinja2

Мы также добавим Bootstrap, он будет загружен из CDN. Однако дополнительные стили можно хранить в другой папке. Мы рассмотрим обслуживание статических файлов в следующих разделах курса.

Создадим новую папку templates, в каталоге нашего проекта. В этой папке будут храниться все наши файлы Jinja, которые представляют собой файлы HTML. Jinja должен определить эту папку путем создания экземпляра Jinja2Templates в FastAPI.

Вверху нашего проекта, добавим следующий код:

from fastapi.templating import Jinja2Templates


app = FastAPI()
templates = Jinja2Templates(directory="templates")

Теперь Jinja понимает, что нужно искать HTML-файлы внутри этой папки шаблонов. Далее перейдем к написанию кода шаблонов.

 

Создание макета шаблона

Создадим файл main.html в папке шаблонов, этот шаблон является базовым или родительским шаблоном для нашего приложения:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CRUD Project FastAPI</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<header>
    <nav class="navar">
        <div class="p-3 mb-2 bg-primary text-white">
            <h1>CRUD Application</h1>
        </div>
    </nav>
</header>
<div class="container-fluid">
    {% block crud_container %}
    {% endblock %}
</div>
</body>
</html>

Другие шаблоны могут наследовать структуру и дизайн этого файла main.html с помощью тегов {% extends %}. Базовый шаблон имеет теги Jinja, а именно теги {% block crud_container %} и {% endblock %}, которые указывают, куда дочерние шаблоны могут вставлять свой контент.

Создадим файл message.html и добавим в него следующий код:

{% extends "main.html" %}

{% block crud_container %}
    <section class="container-fluid">
        <h2>Messages</h2>
        <br>
        <div class="card">
            <ul class="list-group list-group-flush">
                {% for message in messages %}
                <li class="list-group-item">{{ message.id }}. <a href="/message/{{message.id}}">{{ message.text }}</a></li>
                {% endfor %}
            </ul>
        </div>
    </section>
{% endblock %}

В данном коде мы наследуемся от базового шаблона, чтобы следовать принципу DRY(не повторяйся) и выводим в цикле наши записи, в виде маркированного списка выводим ID и сам текст записи. Теперь давайте изменим код вывода всех наших записей из БД(списка).

from fastapi import FastAPI, status, Body, HTTPException, Request
from fastapi.responses import HTMLResponse


@app.get("/")
def get_all_messages(request: Request) -> HTMLResponse:
    return templates.TemplateResponse("message.html", {"request": request, "messages": messages_db})

В этой функции мы получаем фактический запрос(Request) и возвращаем templetes.TemplateResponse(HTMLResponse) с запросом в словаре. Этот словарь называется контекстным словарём. В нем мы передаем сам запрос и нашу БД(список) в виде переменной messages. Если мы добавим оператор печати print(dir(request)), мы увидим, что запрос имеет много важных атрибутов, таких как 'user', 'cookies', 'form', 'get', 'headers', 'path_params', 'query_params', 'url', 'url_for', 'values', которые могут использоваться в шаблонах.

Запустим сервер и проверим работу шаблонов. Мы видим что функция вывода всех записей приняла следующий вид:

Попробуем через нашу документацию добавить несколько записей и перейдем снова на главную страницу:

Мы видим что у нас вывелись все записи, хранящиеся в нашей БД(списке). При нажатии на любую запись, мы перейдем на страницу, которая будет выводить запись из словаря messages_db с принятым message_id из параметра пути.

В следующем шаге мы сделаем ее вывод также в виде шаблона.


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

Здравствуйте!

файл message.html

тег </main> не лишний?

@Николай_Баранов, лишний конечно, исправил, спасибо.