# FastApi

# Общие команды

**Установка**

```bash
pip install fastapi uvicorn
```

**Ручной запуск** (api - имя файла, app - имя объекта FastApi)

```bash
uvicorn api:app --port 8000 --reload
```

**Запуск uvicorn из python скрипта**

Файл main.py

```python
from uvicorn import run
...
app = FastAPI()
...
if __name__ == '__main__':
    run(app="main:app", host='0.0.0.0', port=8000, workers=4, log_level='warning')
    #run(app="main:app", host='0.0.0.0', port=8000, reload=True)
```

**Запросы**

**curl запросы**

```bash
curl -X 'GET' 'http://127.0.0.1:8000/todo' -H 'accept: application/json' 
```

```bash
curl -X 'POST' \ 
'http://127.0.0.1:8000/todo' \ 
-H 'accept: application/json' \ 
-H 'Content-Type: application/json' \ 
-d '{ 
"id": 1, 
"item": "First Todo is to finish this book!" 
}'
```

**Requests**

```
import requests
r = requests.get("http://localhost:8000/hi")
print(r.json())
```

Передача параметров

```
params = {"who": "Mom"}
r = requests.get("http://localhost:8000/hi", params=params)
```

**Httpx**

```
import httpx
r = httpx.get("http://localhost:8000/hi")
print(r.json())
```

**Автоматическая документация**

**Swagger**

```html
http://ip:port/docs
```

**Redoc**

```html
http://ip:port/redoc
```

**Шаблоны Jinja**

Поддерживает шаблоны Jinja при выводе данных (вплоть до циклов).

# Маршрутизация

**Параметризация запросов**

Передача параметров в запросе

```
@app.get("/hi/{who}")
def greet(who):
    return f"Hello? {who}?"
```

Передача параметров в параметре запроса

```
@app.get("/hi")
def greet(who):
    return f"Hello? {who}?"
```

Запрос типа localhost:8000/hi?who=Mom

Параметры передавать можно в параметрах запроса, в заголовках, в теле запроса, кукисах, ...

**Добавление маршрутов**

Основной файл:

```python
from fastapi import FastAPI 
from todo import todo_router 
 
app = FastAPI() 

@app.get("/") 
async def welcome() -> dict: 
    return { 
        "message": "Hello World" 
        } 

app.include_router(todo_router)
```

Файл дополнительных маршрутов

```python
from fastapi import APIRouter 
 
todo_router = APIRouter()

todo_list = [] 
 
@todo_router.post("/todo") 
async def add_todo(todo: dict) -> dict: 
    todo_list.append(todo) 
    return {"message": "Todo added successfully"} 

@todo_router.get("/todo") 
async def retrieve_todos() -> dict: 
    return {"todos": todo_list}
```

Автоматическое добавление маршрутов в основной файл *app* из файлов в директории data/plugins имеющих шаблон имени объекта APIRouter *modulename\_router*

```python
fpath = os.path.join('data', 'plugins')
flist = os.listdir(fpath)
sys.path.insert(0, fpath)
for fname in flist:
    if fname not in ['__pycache__', '__init__.py']:
        m = os.path.splitext(fname)[0]
        impmod = importlib.import_module(m)
        router_name = f'{m}_router'
        if router_name in dir(impmod):
            router_mod = getattr(impmod, router_name)
            app.include_router(router_mod)
```

**Возвращаемые данные**

По умолчанию возвращается JSON, добавляется заголовок Status Code и Content-type: application/json.

При помощи response\_model можно фильтровать отдаваемые данные. Т е можно в отдаваемой модели указать неполный набор.

```python
from typing import List 
 
class TodoItem(BaseModel): 
    item: str 
 
class TodoItems(BaseModel): 
    todos: List[TodoItem]
```

```python
@todo_router.get("/todo", response_model=TodoItems) 
async def retrieve_todo() -> dict: 
    return { 
        "todos": todo_list 
        }
```

У содержащихся в списке словарей будет оставлен только item

**Исключения**

Класс HTTPException принимает три аргумента:

- status\_code: Код состояния, который будет возвращен для этого сбоя
- detail: Сопроводительное сообщение для отправки клиенту
- headers: Необязательный параметр для ответов, требующих заголовков

```python
from fastapi import APIRouter, Path, HTTPException, status 

@todo_router.get("/todo/{todo_id}") 
async def get_single_todo(todo_id: int = Path(..., title="The ID of the todo to retrieve.")) -> dict: 
    for todo in todo_list:
      if todo.id == todo_id: 
        return { "todo": todo } 
    raise HTTPException( 
        status_code=status.HTTP_404_NOT_FOUND, 
        detail="Todo with supplied ID doesn't exist", 
        )
```

Можно переопределить код успешного возврата в декораторе

```python
@todo_router.post("/todo", status_code=201) 
async def add_todo(todo: Todo) -> dict: 
  todo_list.append(todo) 
  return { "message": "Todo added successfully." }
```

# Pydantic

```python
class Item(BaseModel): 
    item: str 
    status: str 
 
class Todo(BaseModel):
    id: int 
    item: Item
```

# Jinja2

<div class="align-center" id="bkmrk-%D0%A4%D0%BE%D1%80%D0%BC%D0%B0%D1%82-jinja2">**Формат Jinja2**</div><div id="bkmrk-%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%B0-j">Переменные шаблона Jinja могут относиться к любому типу или объекту Python, если их можно преобразовать в строки. Тип модели, списка или словаря можно передать шаблону и отобразить его атрибуты, поместив эти атрибуты во второй блок, указанный ранее. </div><div id="bkmrk-%D0%92%D0%B8%D0%B4%D1%8B-%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%81%D0%B0">**Виды синтаксиса**</div><div id="bkmrk-%7B%25-%E2%80%A6-%25%7D-%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D1%8F%D1%8E%D1%89%D0%B8%D0%B5-">{% … %} управляющие структуры</div><div id="bkmrk-%7B%7B-todo.item-%7D%7D-%D0%B2%D1%8B%D0%B2%D0%BE">{{ todo.item }} вывод значений переданных ему выражений  
{# This is a great API book! #} комментарии</div><div id="bkmrk-%D0%98%D0%B5%D1%80%D0%B0%D1%80%D1%85%D0%B8%D1%8F-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2">**Иерархия шаблонов**</div><div id="bkmrk-%D0%A1%D0%BF%D0%BE%D1%81%D0%BE%D0%B1-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-%7B%25-i"><table border="1" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 24.5591%;"></col><col style="width: 75.4409%;"></col></colgroup><thead><tr><td class="align-center">Способ</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td>{% include %}</td><td>Позволяет включить содержимое другого шаблона целиком. ```
<!-- основной шаблон -->
<h1>Главная страница</h1>
{% include 'partials/header.html' %}
<p>Основное содержимое...</p>
```

</td></tr><tr><td>{% extends %} + {% block %}</td><td>Наследование шаблонов и переопределение блоков.

Базовый шаблон

```

<html>
<head>
    <title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
    {% block content %}{% endblock %}
</body>
</html>
```

Дочерний шаблон

```
{% extends "base.html" %}

{% block title %}Custom Title{% endblock %}

{% block content %}
    <h1>Привет, мир!</h1>
    {% include 'partials/footer.html' %}
{% endblock %}
```

</td></tr></tbody></table>

</div><div id="bkmrk-"></div><div class="align-left" id="bkmrk-%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D1%8B%3A">**Фильтры**</div>```python
{{ variable | filter_name(*args) }}
```

<div id="bkmrk-hello%2C-%7B%7B-name%7Ccapit">**Виды фильтров**</div><div id="bkmrk-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-%C2%A0d"><table border="1" style="border-collapse: collapse; width: 100%; height: 636.454px;"><colgroup><col style="width: 23.7133%;"></col><col style="width: 76.2867%;"></col></colgroup><thead><tr style="height: 29.7969px;"><td class="align-center" style="height: 29.7969px;">Название</td><td class="align-center" style="height: 29.7969px;">Описание</td></tr></thead><tbody><tr style="height: 82.9844px;"><td style="height: 82.9844px;"> default(strdefault)</td><td style="height: 82.9844px;">Замена вывода переданного значения, если оно оказывается None

```python
{{ todo.item | default('This is a default todo item') }}
```

</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">escape</td><td style="height: 29.7969px;">Отображение необработанного вывода HTML</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">striptags</td><td style="height: 29.7969px;">Удаление HTML тетов перед отправкой</td></tr><tr style="height: 140.547px;"><td style="height: 140.547px;">int

float

</td><td style="height: 140.547px;">Преобразование типов перед ответом

```python
{{ 3.142 | int }} 
3 
{{ 31 | float }} 
31.0
```

</td></tr><tr style="height: 102.172px;"><td style="height: 102.172px;">join(whitespace)</td><td style="height: 102.172px;">Объединение элементов списка в строку ```python
{{ ['Packt', 'produces', 'great', 'books!'] | join(' ') }} 
Packt produces great books!
```

</td></tr><tr style="height: 102.172px;"><td style="height: 102.172px;">length</td><td style="height: 102.172px;">Длина переданного объекта ```python
Todo count: {{ todos | length }} 
Todo count: 4
```

</td></tr></tbody></table>

</div><div id="bkmrk-%D0%9F%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9-%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80">[Полный список фильтров](https://jinja.palletsprojects.com/en/3.0.x/%20%20templates/#builtin-filters)</div><div id="bkmrk-trim-removes-leading"></div><div id="bkmrk-%D0%A3%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D1%8F%3A">**Условия:**</div>```python
{% if user %}
    Hello, {{ user.name }}!
{% else %}
    Hello, Unknown!
{% endif %}
```

<div id="bkmrk-%7B%25-endif-%25%7D"></div><div id="bkmrk--1"></div><div id="bkmrk-%D0%A6%D0%B8%D0%BA%D0%BB%D1%8B%3A">**Циклы**</div>```python
{% for comment in comments %}
   <b>{{ comment }}</b>
{% endfor %}
```

<div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D"></div><div id="bkmrk-%3C%2Ful%3E">Можно также обратиться к переменной loop.index для получения дополнительной информации</div><div id="bkmrk-%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-"><table border="1" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 36.131%;"></col><col style="width: 63.9882%;"></col></colgroup><thead><tr><td class="align-center">Переменная</td><td class="align-center">Описание</td></tr></thead><tbody><tr><td>loop.index</td><td>Текущее значение итерации (1 - первая итерация)</td></tr><tr><td>loop.index0</td><td>Текущее значение итерации (0 - первая итерация)</td></tr><tr><td>loop.revindex loop.revindex0</td><td>Кол-во оставшихся итераций</td></tr><tr><td>loop.first</td><td>True если первая итерация</td></tr><tr><td>loop.last</td><td>  
</td></tr><tr><td>loop.length</td><td>  
</td></tr><tr><td>loop.pervitem loop.nextitem</td><td>Значение предыдущей/следующей итерации (пусто если не существует)</td></tr></tbody></table>

</div><div id="bkmrk-%D0%9C%D0%B0%D0%BA%D1%80%D0%BE%D1%81%D1%8B%3A">Макросы:</div><div id="bkmrk-%7B%25-macro-render_comm">{% macro render_comment(comment) %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3E%7B%7B-comment-%7D"> &lt;li&gt;{{ comment }}&lt;/li&gt;</div><div id="bkmrk-%7B%25-endmacro-%25%7D">{% endmacro %}</div><div id="bkmrk-%3Cul%3E-1">&lt;ul&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-for-comment-i-1"> {% for comment in comments %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%7B-render_co"> {{ render_comment(comment) }}</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D-1"> {% endfor %}</div><div id="bkmrk-%3C%2Ful%3E-1">&lt;/ul&gt;</div><div id="bkmrk-%D0%9C%D0%B0%D0%BA%D1%80%D0%BE%D1%81%D1%8B-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE-%D0%B8%D0%BC%D0%BF%D0%BE%D1%80%D1%82">Макросы можно импортировать из файлов</div><div id="bkmrk-%7B%25-import-%27macros.ht">{% import 'macros.html' as macros %}</div><div id="bkmrk--2">  
</div><div id="bkmrk--3">  
</div><div id="bkmrk-%D0%92-jinja-%D0%B4%D0%B2%D0%BE%D0%B9%D0%BD%D1%8B%D0%B5-%D1%84%D0%B8%D0%B3%D1%83">В Jinja двойные фигурные скобки {{ }} позволяют получить результат выражение, переменную или вызвать функцию и вывести значение в шаблоне.</div><div id="bkmrk-class-foo%3A">class Foo:</div><div id="bkmrk-%C2%A0def-__str__%28self%29%3A"> def __str__(self):</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0return-%22this-is"> return "This is an instance of Foo class"</div><div id="bkmrk-template%28%22%7B%7B-var-%7D%7D%22">Template("{{ var }}").render(var=Foo())</div><div id="bkmrk-%27this-is-an-instance">'This is an instance of Foo class'</div><div id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D0%BE%D0%B1%D1%80%D0%B0%D1%82%D0%B8%D1%82%D1%81%D1%8F-%D0%BA-%D0%B8%D0%BD%D0%B4">Если обратится к индексу, который не существует, Jinja просто выведет пустую строку.</div><div id="bkmrk--4">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B7%D0%BE%D0%B2-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">Вызов функции</div><div id="bkmrk-%D0%92-jinja-%D0%B4%D0%BB%D1%8F-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5">В Jinja для определения функции ее нужно просто вызвать.</div><div id="bkmrk-%C2%A0def-foo%28%29%3A"> def foo():</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0return-%22foo%28%29-c"> return "foo() called"</div><div id="bkmrk-template%28%22%7B%7B-foo%28%29-%7D">Template("{{ foo() }}").render(foo=foo)</div><div id="bkmrk-%27foo%28%29-called%27">'foo() called'</div><div id="bkmrk--5">  
</div><div id="bkmrk-%D0%9E%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B">Объявление переменных</div><div id="bkmrk--6">  
</div><div id="bkmrk-%D0%92%D0%BD%D1%83%D1%82%D1%80%D0%B8-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%B0-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE">Внутри шаблона можно задать переменную с помощью инструкции set.</div><div id="bkmrk--7">  
</div><div id="bkmrk-%7B%25-set-fruit-%3D-%27appl">{% set fruit = 'apple' %}</div><div id="bkmrk--8">  
</div><div id="bkmrk-%7B%25-set-name%2C-age-%3D-%27">{% set name, age = 'Tom', 20 %}</div><div id="bkmrk--9">  
</div><div id="bkmrk-%D0%9F%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D1%8F%D1%8E">Переменные определяются для хранения результатов сложных операций, так чтобы их можно было использовать дальше в шаблоне. Переменные, определенные вне управляющих конструкций (о них дальше), ведут себя как глобальные переменные и доступны внутри любой структуры. Тем не менее переменные, созданные внутри конструкций, ведут себя как локальные переменные и видимы только внутри этих конкретных конструкций. Единственное исключение — инструкция if.</div><div id="bkmrk-%D0%A6%D0%B8%D0%BA%D0%BB-%D0%B8-%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%BD%D1%8B%D0%B5-%D0%B2%D1%8B%D1%80%D0%B0">Цикл и условные выражения</div><div id="bkmrk-%D0%A0%D0%B5%D0%BA%D0%BB%D0%B0%D0%BC%D0%B0">Реклама</div><div id="bkmrk--10">  
</div><div id="bkmrk-%D0%A3%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D1%8F%D1%8E%D1%89%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA">Управляющие конструкции позволяют добавлять в шаблоны элементы управления потоком и циклы. По умолчанию, управляющие конструкции используют разделитель {% … %} вместо двойных фигурных скобок {{ ... }}.</div><div id="bkmrk-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D1%8F-if">Инструкция if</div><div id="bkmrk--11">  
</div><div id="bkmrk-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D1%8F-if-%D0%B2-jinj">Инструкция if в Jinja имитирует выражение if в Python, а значение условия определяет набор инструкции. Например:</div><div id="bkmrk--12">  
</div><div id="bkmrk-%7B%25-if-bookmarks-%25%7D">{% if bookmarks %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Euser-has-some"> &lt;p&gt;User has some bookmarks&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-1">{% endif %}</div><div id="bkmrk--13">  
</div><div id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5">Если значение переменной bookmarks – True, тогда будет выведена строка &lt;p&gt;User has some bookmarks&lt;/p&gt;. Стоит запомнить, что в Jinja, если у переменной нет значения, она возвращает False.</div><div id="bkmrk--14">  
</div><div id="bkmrk-%D0%A2%D0%B0%D0%BA%D0%B6%D0%B5-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE">Также можно использовать условия elif и else, как в обычном коде Python. Например:</div><div id="bkmrk--15">  
</div><div id="bkmrk-%7B%25-if-user.newbie-%25%7D">{% if user.newbie %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Edisplay-newbi"> &lt;p&gt;Display newbie stages&lt;/p&gt;</div><div id="bkmrk-%7B%25-elif-user.pro-%25%7D">{% elif user.pro %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Edisplay-pro-s"> &lt;p&gt;Display pro stages&lt;/p&gt;</div><div id="bkmrk-%7B%25-elif-user.ninja-%25">{% elif user.ninja %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Edisplay-ninja"> &lt;p&gt;Display ninja stages&lt;/p&gt;</div><div id="bkmrk-%7B%25-else-%25%7D-1">{% else %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Eyou-have-comp"> &lt;p&gt;You have completed all stages&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-2">{% endif %}</div><div id="bkmrk--16">  
</div><div id="bkmrk-%D0%A3%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D1%8F%D1%8E%D1%89%D0%B8%D0%B5-%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86">Управляющие инструкции также могут быть вложенными. Например:</div><div id="bkmrk--17">  
</div><div id="bkmrk-%7B%25-if-user-%25%7D-1">{% if user %}</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-if-user.newbi"> {% if user.newbie %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3Edisplay-n"> &lt;p&gt;Display newbie stages&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-elif-user.pro"> {% elif user.pro %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3Edisplay-p"> &lt;p&gt;Display pro stages&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-elif-user.nin"> {% elif user.ninja %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3Edisplay-n-1"> &lt;p&gt;Display ninja stages&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-else-%25%7D"> {% else %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3Eyou-have-"> &lt;p&gt;You have completed all states&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endif-%25%7D"> {% endif %}</div><div id="bkmrk-%7B%25-else-%25%7D-2">{% else %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Euser-is-not-d"> &lt;p&gt;User is not defined&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-3">{% endif %}</div><div id="bkmrk--18">  
</div><div id="bkmrk-%D0%A0%D0%B5%D0%BA%D0%BB%D0%B0%D0%BC%D0%B0-1">Реклама</div><div id="bkmrk--19">  
</div><div id="bkmrk-%D0%92-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D1%81%D0%BB%D1%83%D1%87%D0%B0">В определенных случаях достаточно удобно записывать инструкцию if в одну строку. Jinja поддерживает такой тип записи, но называет это выражением if, потому что оно записывается с помощью двойных фигурных скобок {{ … }}, а не {% … %}. Например:</div><div id="bkmrk--20">  
</div><div id="bkmrk-%7B%7B-%22user-is-logged-i">{{ "User is logged in" if loggedin else "User is not logged in" }}</div><div id="bkmrk--21">  
</div><div id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C-%D0%B5%D1%81%D0%BB%D0%B8-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%B0">Здесь если переменная loggedin вернет True, тогда будет выведена строка “User is logged in”. В противном случае — “User is not logged in”.</div><div id="bkmrk--22">  
</div><div id="bkmrk-%D0%A3%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B5-else-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7">Условие else использовать необязательно. Если его нет, тогда блок else вернет объект undefined.</div><div id="bkmrk--23">  
</div><div id="bkmrk-%7B%7B-%22user-is-logged-i-1">{{ "User is logged in" if loggedin }}</div><div id="bkmrk--24">  
</div><div id="bkmrk-%D0%97%D0%B4%D0%B5%D1%81%D1%8C%2C-%D0%B5%D1%81%D0%BB%D0%B8-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD">Здесь, если переменная loggedin вернет True, будет выведена строка “User is logged in”. В противном случае — ничего.</div><div id="bkmrk--25">  
</div><div id="bkmrk-%D0%9A%D0%B0%D0%BA-%D0%B8-%D0%B2-python-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE">Как и в Python можно использовать операторы сравнения, присваивания и логические операторы для управляющих конструкций, чтобы создавать более сложные условия. Вот несколько примеров:</div><div id="bkmrk--26">  
</div><div id="bkmrk-%7B%23-%D0%95%D1%81%D0%BB%D0%B8-user.count-%D1%80">{# Если user.count ревен 1000, код '&lt;p&gt;User count is 1000&lt;/p&gt;' отобразится #}</div><div id="bkmrk-%7B%25-if-users.count-%3D%3D">{% if users.count == 1000 %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Euser-count-is"> &lt;p&gt;User count is 1000&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-4">{% endif %}</div><div id="bkmrk--27">  
</div><div id="bkmrk-%7B%23-%D0%95%D1%81%D0%BB%D0%B8-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-10">{# Если выражение 10 &gt;= 2 верно, код '&lt;p&gt;10 &gt;= 2&lt;/p&gt;' отобразится #}</div><div id="bkmrk-%7B%25-if-10-%3E%3D-2-%25%7D">{% if 10 &gt;= 2 %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3E10-%3E%3D-2%3C%2Fp%3E"> &lt;p&gt;10 &gt;= 2&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-5">{% endif %}</div><div id="bkmrk--28">  
</div><div id="bkmrk-%7B%23-%D0%95%D1%81%D0%BB%D0%B8-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%22c">{# Если выражение "car" &lt;= "train" верно, код '&lt;p&gt;car &lt;= train&lt;/p&gt;' отобразится #}</div><div id="bkmrk-%7B%25-if-%22car%22-%3C%3D-%22trai">{% if "car" &lt;= "train" %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ecar-%3C%3D-train%3C"> &lt;p&gt;car &lt;= train&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-6">{% endif %}</div><div id="bkmrk--29">  
</div><div id="bkmrk-%7B%23">{#</div><div id="bkmrk-%C2%A0-%C2%A0-%D0%95%D1%81%D0%BB%D0%B8-user-%D0%B7%D0%B0%D0%BB%D0%BE%D0%B3%D0%B8"> Если user залогинен и superuser, код</div><div id="bkmrk-%C2%A0-%C2%A0-%27%3Cp%3Euser-is-logg"> '&lt;p&gt;User is logged in and is a superuser&lt;/p&gt;' отобразится</div><div id="bkmrk-%23%7D">\#}</div><div id="bkmrk-%7B%25-if-user.loggedin-">{% if user.loggedin and user.is_superuser %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Euser-is-logge"> &lt;p&gt;User is logged in and is a superuser&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-7">{% endif %}</div><div id="bkmrk--30">  
</div><div id="bkmrk-%7B%23-1">{#</div><div id="bkmrk-%C2%A0-%C2%A0-%D0%95%D1%81%D0%BB%D0%B8-user-%D1%8F%D0%B2%D0%BB%D1%8F%D0%B5%D1%82"> Если user является superuser, moderator или author, код</div><div id="bkmrk-%C2%A0-%C2%A0-%27%3Ca-href%3D%22%23%22%3Eedi"> '&lt;a href="#"&gt;Edit&lt;/a&gt;' отобразится</div><div id="bkmrk-%23%7D-1">\#}</div><div id="bkmrk-%7B%25-if-user.is_superu">{% if user.is_superuser or user.is_moderator or user.is_author %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ca-href%3D%22%23%22%3Eedit"> &lt;a href="#"&gt;Edit&lt;/a&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-8">{% endif %}</div><div id="bkmrk--31">  
</div><div id="bkmrk-%7B%23-2">{#</div><div id="bkmrk-%C2%A0-%C2%A0-%D0%95%D1%81%D0%BB%D0%B8-user-%D0%B8-curr"> Если user и current_user один и тот же объект, код </div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Euser-and-curr"> &lt;p&gt;user and current_user are same&lt;/p&gt; отобразится</div><div id="bkmrk-%23%7D-2">\#}</div><div id="bkmrk-%7B%25-if-user-is-curren">{% if user is current_user %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Euser-and-curr-1"> &lt;p&gt;user and current_user are same&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-9">{% endif %}</div><div id="bkmrk--32">  
</div><div id="bkmrk-%7B%23-3">{#</div><div id="bkmrk-%C2%A0-%C2%A0-%D0%95%D1%81%D0%BB%D0%B8-%22flask%22-%D0%B5%D1%81%D1%82"> Если "Flask" есть в списке, код </div><div id="bkmrk-%C2%A0-%C2%A0-%27%3Cp%3Eflask-is-in-"> '&lt;p&gt;Flask is in the dictionary&lt;/p&gt;' отобразится</div><div id="bkmrk-%23%7D-3">\#}</div><div id="bkmrk-%7B%25-if-%5B%22flask%22%5D-in-%5B">{% if ["Flask"] in ["Django", "web2py", "Flask"] %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Eflask-is-in-t"> &lt;p&gt;Flask is in the dictionary&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-10">{% endif %}</div><div id="bkmrk--33">  
</div><div id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D1%8F-%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D1%8F">Если условия становятся слишком сложными, или просто есть желание поменять приоритет оператора, можно обернуть выражения скобками ():</div><div id="bkmrk--34">  
</div><div id="bkmrk-%7B%25-if-%28user.marks-%3E-">{% if (user.marks &gt; 80) and (user.marks &lt; 90) %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Eyou-grade-is-"> &lt;p&gt;You grade is B&lt;/p&gt;</div><div id="bkmrk-%7B%25-endif-%25%7D-11">{% endif %}</div><div id="bkmrk--35">  
</div><div id="bkmrk-%D0%A6%D0%B8%D0%BA%D0%BB-for">Цикл for</div><div id="bkmrk--36">  
</div><div id="bkmrk-%D0%A6%D0%B8%D0%BA%D0%BB-for-%D0%BF%D0%BE%D0%B7%D0%B2%D0%BE%D0%BB%D1%8F%D0%B5%D1%82-%D0%BF">Цикл for позволяет перебирать последовательность. Например:</div><div id="bkmrk--37">  
</div><div id="bkmrk-%7B%25-set-user_list-%3D-%5B">{% set user_list = ['tom', 'jerry', 'spike'] %}</div><div id="bkmrk--38">  
</div><div id="bkmrk-%3Cul%3E-2">&lt;ul&gt;</div><div id="bkmrk-%7B%25-for-user-in-user_">{% for user in user_list %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3E%7B%7B-user-%7D%7D%3C%2F"> &lt;li&gt;{{ user }}&lt;/li&gt;</div><div id="bkmrk-%7B%25-endfor-%25%7D">{% endfor %}</div><div id="bkmrk-%3C%2Ful%3E-2">&lt;/ul&gt;</div><div id="bkmrk--39">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B2%D0%BE%D0%B4%3A">Вывод:</div><div id="bkmrk--40">  
</div><div id="bkmrk-%3Cul%3E-3">&lt;ul&gt;</div><div id="bkmrk--41">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Etom%3C%2Fli%3E"> &lt;li&gt;tom&lt;/li&gt;</div><div id="bkmrk--42">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Ejerry%3C%2Fli%3E"> &lt;li&gt;jerry&lt;/li&gt;</div><div id="bkmrk--43">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Espike%3C%2Fli%3E"> &lt;li&gt;spike&lt;/li&gt;</div><div id="bkmrk--44">  
</div><div id="bkmrk-%3C%2Ful%3E-3">&lt;/ul&gt;</div><div id="bkmrk--45">  
</div><div id="bkmrk-%D0%92%D0%BE%D1%82-%D0%BA%D0%B0%D0%BA-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE-%D0%BF%D0%B5%D1%80%D0%B5%D0%B1%D0%B8">Вот как можно перебирать значения словаря:</div><div id="bkmrk--46">  
</div><div id="bkmrk-%7B%25-set-employee-%3D-%7B-">{% set employee = { 'name': 'tom', 'age': 25, 'designation': 'Manager' } %}</div><div id="bkmrk--47">  
</div><div id="bkmrk-%3Cul%3E-4">&lt;ul&gt;</div><div id="bkmrk-%7B%25-for-key-in-employ">{% for key in employee.items() %}</div><div id="bkmrk-%3Cli%3E%7B%7B-key-%7D%7D-%3A-%7B%7B-e">&lt;li&gt;{{ key }} : {{ employee[key] }}&lt;/li&gt;</div><div id="bkmrk-%7B%25-endfor-%25%7D-1">{% endfor %}</div><div id="bkmrk-%3C%2Ful%3E-4">&lt;/ul&gt;</div><div id="bkmrk--48">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B2%D0%BE%D0%B4%3A-1">Вывод:</div><div id="bkmrk--49">  
</div><div id="bkmrk-%3Cul%3E-5">&lt;ul&gt;</div><div id="bkmrk--50">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Edesignation-"> &lt;li&gt;designation : Manager&lt;/li&gt;</div><div id="bkmrk--51">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Ename-%3A-tom%3C%2F"> &lt;li&gt;name : tom&lt;/li&gt;</div><div id="bkmrk--52">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Eage-%3A-25%3C%2Fli"> &lt;li&gt;age : 25&lt;/li&gt;</div><div id="bkmrk--53">  
</div><div id="bkmrk-%3C%2Ful%3E-5">&lt;/ul&gt;</div><div id="bkmrk--54">  
</div><div id="bkmrk-%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%87%D0%B0%D0%BD%D0%B8%D0%B5%3A-%D0%B2-python">Примечание: в Python элементы словаря не хранятся в конкретном порядке, поэтому вывод может отличаться.</div><div id="bkmrk--55">  
</div><div id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D0%BD%D1%83%D0%B6%D0%BD%D0%BE-%D0%BF%D0%BE%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%8C-">Если нужно получить ключ и значение словаря вместе, используйте метод items().</div><div id="bkmrk--56">  
</div><div id="bkmrk-%7B%25-set-employee-%3D-%7B--1">{% set employee = { 'name': 'tom', 'age': 25, 'designation': 'Manager' } %}</div><div id="bkmrk--57">  
</div><div id="bkmrk-%3Cul%3E-6">&lt;ul&gt;</div><div id="bkmrk-%7B%25-for-key%2C-value-in">{% for key, value in employee.items() %}</div><div id="bkmrk-%3Cli%3E%7B%7B-key-%7D%7D-%3A-%7B%7B-v">&lt;li&gt;{{ key }} : {{ value }}&lt;/li&gt;</div><div id="bkmrk-%7B%25-endfor-%25%7D-2">{% endfor %}</div><div id="bkmrk-%3C%2Ful%3E-6">&lt;/ul&gt;</div><div id="bkmrk--58">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B2%D0%BE%D0%B4%3A-2">Вывод:</div><div id="bkmrk--59">  
</div><div id="bkmrk-%3Cul%3E-7">&lt;ul&gt;</div><div id="bkmrk--60">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Edesignation--1"> &lt;li&gt;designation : Manager&lt;/li&gt;</div><div id="bkmrk--61">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Ename-%3A-tom%3C%2F-1"> &lt;li&gt;name : tom&lt;/li&gt;</div><div id="bkmrk--62">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Eage-%3A-25%3C%2Fli-1"> &lt;li&gt;age : 25&lt;/li&gt;</div><div id="bkmrk--63">  
</div><div id="bkmrk-%3C%2Ful%3E-7">&lt;/ul&gt;</div><div id="bkmrk--64">  
</div><div id="bkmrk-%D0%A6%D0%B8%D0%BA%D0%BB-for-%D1%82%D0%B0%D0%BA%D0%B6%D0%B5-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82">Цикл for также может использовать дополнительное условие else, как в Python, но зачастую способ его применения отличается. Стоит вспомнить, что в Python, если else идет следом за циклом for, условие else выполняется только в том случае, если цикл завершается после перебора всей последовательности, или если она пуста. Оно не выполняется, если цикл остановить оператором break.</div><div id="bkmrk--65">  
</div><div id="bkmrk-%D0%9A%D0%BE%D0%B3%D0%B4%D0%B0-%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B5-else-%D0%B8">Когда условие else используется в цикле for в Jinja, оно исполняется только в том случае, если последовательность пустая или не определена. Например:</div><div id="bkmrk-%D0%A0%D0%B5%D0%BA%D0%BB%D0%B0%D0%BC%D0%B0-2">Реклама</div><div id="bkmrk--66">  
</div><div id="bkmrk-%7B%25-set-user_list-%3D-%5B-1">{% set user_list = [] %}</div><div id="bkmrk--67">  
</div><div id="bkmrk-%3Cul%3E-8">&lt;ul&gt;</div><div id="bkmrk-%7B%25-for-user-in-user_-1">{% for user in user_list %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3E%7B%7B-user-%7D%7D%3C%2F-1"> &lt;li&gt;{{ user }}&lt;/li&gt;</div><div id="bkmrk-%7B%25-else-%25%7D-3">{% else %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Euser_list-is"> &lt;li&gt;user_list is empty&lt;/li&gt;</div><div id="bkmrk-%7B%25-endfor-%25%7D-3">{% endfor %}</div><div id="bkmrk-%3C%2Ful%3E-8">&lt;/ul&gt;</div><div id="bkmrk--68">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B2%D0%BE%D0%B4%3A-3">Вывод:</div><div id="bkmrk--69">  
</div><div id="bkmrk-%3Cul%3E-9">&lt;ul&gt;</div><div id="bkmrk--70">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3Euser_list-is-1"> &lt;li&gt;user_list is empty&lt;/li&gt;</div><div id="bkmrk--71">  
</div><div id="bkmrk-%3C%2Ful%3E-9">&lt;/ul&gt;</div><div id="bkmrk--72">  
</div><div id="bkmrk-%D0%9F%D0%BE-%D0%B0%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8-%D1%81-%D0%B2%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD">По аналогии с вложенными инструкциями if, можно использовать вложенные циклы for. На самом деле, любые управляющие конструкции можно вкладывать одна в другую.</div><div id="bkmrk--73">  
</div><div id="bkmrk-%7B%25-for-user-in-user_-2">{% for user in user_list %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3E%7B%7B-user.full_"> &lt;p&gt;{{ user.full_name }}&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3E"> &lt;p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cul-class%3D%22f"> &lt;ul class="follower-list"&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-for-f"> {% for follower in user.followers %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%7B%7B-f"> &lt;li&gt;{{ follower }}&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-endfo"> {% endfor %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3C%2Ful%3E"> &lt;/ul&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3C%2Fp%3E"> &lt;/p&gt;</div><div id="bkmrk-%7B%25-endfor-%25%7D-4">{% endfor %}</div><div id="bkmrk--74">  
</div><div id="bkmrk-%D0%A6%D0%B8%D0%BA%D0%BB-for-%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D1%8F">Цикл for предоставляет специальную переменную loop для отслеживания прогресса цикла. Например:</div><div id="bkmrk--75">  
</div><div id="bkmrk-%3Cul%3E-10">&lt;ul&gt;</div><div id="bkmrk-%7B%25-for-user-in-user_-3">{% for user in user_list %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3E%7B%7B-loop.inde"> &lt;li&gt;{{ loop.index }} - {{ user }}&lt;/li&gt;</div><div id="bkmrk-%7B%25-endfor-%25%7D-5">{% endfor %}</div><div id="bkmrk-%3C%2Ful%3E-10">&lt;/ul&gt;</div><div id="bkmrk--76">  
</div><div id="bkmrk-loop.index-%D0%B2%D0%BD%D1%83%D1%82%D1%80%D0%B8-%D1%86%D0%B8">loop.index внутри цикла for начинает отсчет с 1. В таблице упомянуты остальные широко используемые атрибуты переменной loop.</div><div id="bkmrk-%D0%9C%D0%B5%D1%82%D0%BE%D0%B4-%D0%97%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5">Метод Значение</div><div id="bkmrk-loop.index0-%D1%82%D0%BE-%D0%B6%D0%B5-%D1%81%D0%B0">loop.index0 то же самое что и loop.index, но с индексом 0, то есть, начинает считать с 0, а не с 1.</div><div id="bkmrk-loop.revindex-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0">loop.revindex возвращает номер итерации с конца цикла (считает с 1).</div><div id="bkmrk-loop.revindex0-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80">loop.revindex0 возвращает номер итерации с конца цикла (считает с 0).</div><div id="bkmrk-loop.first-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%89%D0%B0%D0%B5">loop.first возвращает True, если итерация первая. В противном случае — False.</div><div id="bkmrk-loop.last-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%89%D0%B0%D0%B5%D1%82">loop.last возвращает True, если итерация последняя. В противном случае — False.</div><div id="bkmrk-loop.length-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%89%D0%B0">loop.length возвращает длину цикла(количество итераций).</div><div id="bkmrk--77">  
</div><div id="bkmrk-%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%87%D0%B0%D0%BD%D0%B8%D0%B5%3A-%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9-%D1%81">Примечание: полный список есть в документации Flask.</div><div id="bkmrk-%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D1%8B">Фильтры</div><div id="bkmrk--78">  
</div><div id="bkmrk-%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D1%8B-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D1%8F%D1%8E%D1%82-%D0%BF%D0%B5%D1%80">Фильтры изменяют переменные до процесса рендеринга. Синтаксис использования фильтров следующий:</div><div id="bkmrk--79">  
</div><div id="bkmrk-variable_or_value%7Cfi">variable_or_value|filter_name</div><div id="bkmrk--80">  
</div><div id="bkmrk-%D0%92%D0%BE%D1%82-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%3A">Вот пример:</div><div id="bkmrk--81">  
</div><div id="bkmrk-%7B%7B-comment%7Ctitle-%7D%7D">{{ comment|title }}</div><div id="bkmrk--82">  
</div><div id="bkmrk-%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80-title-%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82-">Фильтр title делает заглавной первую букву в каждом слове. Если значение переменной comment — "dust in the wind", то вывод будет "Dust In The Wind".</div><div id="bkmrk--83">  
</div><div id="bkmrk-%D0%9C%D0%BE%D0%B6%D0%BD%D0%BE-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D0%BD">Можно использовать несколько фильтров, чтобы точнее настраивать вывод. Например:</div><div id="bkmrk--84">  
</div><div id="bkmrk-%7B%7B-full_name%7Cstripta">{{ full_name|striptags|title }}</div><div id="bkmrk--85">  
</div><div id="bkmrk-%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80-striptags-%D1%83%D0%B4%D0%B0">Фильтр striptags удалит из переменной все HTML-теги. В приведенном выше коде сначала будет применен фильтр striptags, а затем — title.</div><div id="bkmrk--86">  
</div><div id="bkmrk-%D0%A3-%D0%BD%D0%B5%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D1%85-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D0%BE%D0%B2">У некоторых фильтров есть аргументы. Чтобы передать их фильтру, нужно вызвать фильтр как функцию. Например:</div><div id="bkmrk--87">  
</div><div id="bkmrk-%7B%7B-number%7Cround%282%29-%7D">{{ number|round(2) }}</div><div id="bkmrk--88">  
</div><div id="bkmrk-%D0%A4%D0%B8%D0%BB%D1%8C%D1%82%D1%80-round-%D0%BE%D0%BA%D1%80%D1%83%D0%B3%D0%BB%D1%8F">Фильтр round округляет число до конкретного количества символов.</div><div id="bkmrk--89">  
</div><div id="bkmrk-%D0%92-%D1%81%D0%BB%D0%B5%D0%B4%D1%83%D1%8E%D1%89%D0%B5%D0%B9-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B5-">В следующей таблице указаны широко используемые фильтры.</div><div id="bkmrk-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5">Название Описание</div><div id="bkmrk-upper-%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82-%D0%B2%D1%81%D0%B5-%D1%81%D0%B8%D0%BC">upper делает все символы заглавными</div><div id="bkmrk-lower-%D0%BF%D1%80%D0%B8%D0%B2%D0%BE%D0%B4%D0%B8%D1%82-%D0%B2%D1%81%D0%B5-%D1%81">lower приводит все символы к нижнему регистру</div><div id="bkmrk-capitalize-%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82-%D0%B7%D0%B0">capitalize делает заглавной первую букву и приводит остальные к нижнему регистру</div><div id="bkmrk-escape-%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B8%D1%80%D1%83%D0%B5%D1%82-%D0%B7%D0%BD">escape экранирует значение</div><div id="bkmrk-safe-%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D1%82%D0%B2%D1%80%D0%B0%D1%89%D0%B0%D0%B5%D1%82-%D1%8D">safe предотвращает экранирование</div><div id="bkmrk-length-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%89%D0%B0%D0%B5%D1%82-%D0%BA%D0%BE">length возвращает количество элементов в последовательности</div><div id="bkmrk-trim-%D1%83%D0%B4%D0%B0%D0%BB%D1%8F%D0%B5%D1%82-%D0%BF%D1%83%D1%81%D1%82%D1%8B%D0%B5-">trim удаляет пустые символы в начале и в конце</div><div id="bkmrk-random-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%89%D0%B0%D0%B5%D1%82-%D1%81%D0%BB">random возвращает случайный элемент последовательности</div><div id="bkmrk--90">  
</div><div id="bkmrk-%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%87%D0%B0%D0%BD%D0%B8%D0%B5%3A-%D0%BF%D0%BE%D0%BB%D0%BD%D1%8B%D0%B9-%D1%81-1">Примечание: полный список фильтров доступен здесь.</div><div id="bkmrk-%D0%9C%D0%B0%D0%BA%D1%80%D0%BE%D1%81%D1%8B">Макросы</div><div id="bkmrk--91">  
</div><div id="bkmrk-%D0%9C%D0%B0%D0%BA%D1%80%D0%BE%D1%81%D1%8B-%D0%B2-jinja-%D0%BD%D0%B0%D0%BF%D0%BE">Макросы в Jinja напоминают функции в Python. Суть в том, чтобы сделать код, который можно использовать повторно, просто присвоив ему название. Например:</div><div id="bkmrk--92">  
</div><div id="bkmrk-%7B%25-macro-render_post">{% macro render_posts(post_list, sep=False) %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cdiv%3E"> &lt;div&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-for-post-"> {% for post in post_list %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Ch2%3E%7B%7B-p"> &lt;h2&gt;{{ post.title }}&lt;/h2&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Carticle"> &lt;article&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%7B-p"> {{ post.html|safe }}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3C%2Farticl"> &lt;/article&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D"> {% endfor %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-if-sep-%25%7D"> {% if sep %}&lt;hr&gt;{% endif %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3C%2Fdiv%3E"> &lt;/div&gt;</div><div id="bkmrk-%7B%25-endmacro-%25%7D-1">{% endmacro %}</div><div id="bkmrk--93">  
</div><div id="bkmrk-%D0%92-%D1%8D%D1%82%D0%BE%D0%BC-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D0%B5-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0">В этом примере создан макрос render_posts, который принимает обязательный аргумент post_list и необязательный аргумент sep. Использовать его нужно следующим образом:</div><div id="bkmrk--94">  
</div><div id="bkmrk-%7B%7B-render_posts%28post">{{ render_posts(posts) }}</div><div id="bkmrk--95">  
</div><div id="bkmrk-%D0%9E%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BC%D0%B0%D0%BA%D1%80%D0%BE%D1%81%D0%B0-">Определение макроса должно идти до первого вызова, иначе выйдет ошибка.</div><div id="bkmrk-%D0%A0%D0%B5%D0%BA%D0%BB%D0%B0%D0%BC%D0%B0-3">Реклама</div><div id="bkmrk--96">  
</div><div id="bkmrk-%D0%92%D0%BC%D0%B5%D1%81%D1%82%D0%BE-%D1%82%D0%BE%D0%B3%D0%BE-%D1%87%D1%82%D0%BE%D0%B1%D1%8B-%D0%B8%D1%81">Вместо того чтобы использовать макросы прямо в шаблоне, лучше хранить их в отдельном файле и импортировать по надобности.</div><div id="bkmrk--97">  
</div><div id="bkmrk-%D0%9F%D1%80%D0%B5%D0%B4%D0%BF%D0%BE%D0%BB%D0%BE%D0%B6%D0%B8%D0%BC%2C-%D0%B2%D1%81%D0%B5-%D0%BC%D0%B0%D0%BA">Предположим, все макросы хранятся в файле macros.html в папке templates. Чтобы импортировать их из файла, нужно использовать инструкцию import:</div><div id="bkmrk--98">  
</div><div id="bkmrk-%7B%25-import-%22macros.ht">{% import "macros.html" as macros %}</div><div id="bkmrk--99">  
</div><div id="bkmrk-%D0%A2%D0%B5%D0%BF%D0%B5%D1%80%D1%8C-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D1%82%D1%8C">Теперь можно ссылаться на макросы в файле macros.html с помощью переменной macros. Например:</div><div id="bkmrk--100">  
</div><div id="bkmrk-%7B%7B-macros.render_pos">{{ macros.render_posts(posts) }}</div><div id="bkmrk--101">  
</div><div id="bkmrk-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D1%8F-%7B%25-import">Инструкция {% import “macros.html” as macros %} импортирует все макросы и переменные (определенные на высшем уровне) из файла macros.html в шаблон. Также можно импортировать определенные макросы с помощью from:</div><div id="bkmrk--102">  
</div><div id="bkmrk-%7B%25-from-%22macros.html">{% from "macros.html" import render_posts %}</div><div id="bkmrk--103">  
</div><div id="bkmrk-%D0%9F%D1%80%D0%B8-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B8-%D0%BC%D0%B0">При использовании макросов будут ситуации, когда потребуется передать им произвольное число аргументов.</div><div id="bkmrk--104">  
</div><div id="bkmrk-%D0%9F%D0%BE-%D0%B0%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8-%D1%81-%2Aargs-">По аналогии с *args и **kwargs в Python внутри макросов можно получить доступ к varargs и kwargs.</div><div id="bkmrk--105">  
</div><div id="bkmrk-varags%3A-%D1%81%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D1%8F%D0%B5%D1%82-%D0%B4%D0%BE">varags: сохраняет дополнительные позиционные аргументы, переданные макросу, в виде кортежа.</div><div id="bkmrk--106">  
</div><div id="bkmrk-lwargs%3A-%D1%81%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D1%8F%D0%B5%D1%82-%D0%B4%D0%BE">lwargs: сохраняет дополнительные позиционные аргументы, переданные макросу, в виде словаря.</div><div id="bkmrk--107">  
</div><div id="bkmrk-%D0%A5%D0%BE%D1%82%D1%8F-%D0%BA-%D0%BD%D0%B8%D0%BC-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE-%D0%BF%D0%BE%D0%BB">Хотя к ним можно получить доступ внутри макроса, объявлять их отдельно в заголовке макроса не нужно. Вот пример:</div><div id="bkmrk--108">  
</div><div id="bkmrk-%7B%25-macro-custom_rend">{% macro custom_renderer(para) %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3E%7B%7B-para-%7D%7D%3C%2Fp"> &lt;p&gt;{{ para }}&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Evarargs%3A-%7B%7B-v"> &lt;p&gt;varargs: {{ varargs }}&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ekwargs%3A-%7B%7B-kw"> &lt;p&gt;kwargs: {{ kwargs }}&lt;/p&gt;</div><div id="bkmrk-%7B%25%C2%A0-endmacro%C2%A0-%25%7D">{% endmacro %}</div><div id="bkmrk--109">  
</div><div id="bkmrk-%7B%7B-custom_renderer%28%22">{{ custom_renderer("some content", "apple", name='spike', age=15) }}</div><div id="bkmrk--110">  
</div><div id="bkmrk-%D0%92-%D1%8D%D1%82%D0%BE%D0%BC-%D1%81%D0%BB%D1%83%D1%87%D0%B0%D0%B5-%D0%B4%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD">В этом случае дополнительный позиционный аргумент, "apple", присваивается varargs, а дополнительные аргументы-ключевые слова (name=’spike’, age=15) — kwargs.</div><div id="bkmrk-%D0%AD%D0%BA%D1%80%D0%B0%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5">Экранирование</div><div id="bkmrk--111">  
</div><div id="bkmrk-jinja-%D0%BF%D0%BE-%D1%83%D0%BC%D0%BE%D0%BB%D1%87%D0%B0%D0%BD%D0%B8%D1%8E-%D0%B0">Jinja по умолчанию автоматически экранирует вывод переменной в целях безопасности. Поэтому если переменная содержит, например, такой HTML-код: "&lt;p&gt;Escaping in Jinja&lt;/p&gt;", он отрендерится в виде "&amp;lt;p&amp;gt;Escaping in Jinja&amp;lt;/p&amp;gt;". Благодаря этому HTML-коды будут отображаться в браузере, а не интерпретироваться. Если есть уверенность, что данные безопасны и их точно можно рендерить, стоит воспользоваться фильтром safe. Например:</div><div id="bkmrk--112">  
</div><div id="bkmrk-%7B%25-set-html-%3D-%22%3Cp%3Ees">{% set html = "&lt;p&gt;Escaping in Jinja&lt;/p&gt;" %}</div><div id="bkmrk-%7B%7B-html%7Csafe-%7D%7D">{{ html|safe }}</div><div id="bkmrk--113">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B2%D0%BE%D0%B4%3A-4">Вывод:</div><div id="bkmrk--114">  
</div><div id="bkmrk-%3Cp%3Eescaping-in-jinja">&lt;p&gt;Escaping in Jinja&lt;/p&gt;</div><div id="bkmrk--115">  
</div><div id="bkmrk-%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80-">Использовать фильтр safe в большом блоке кода будет неудобно, поэтому в Jinja есть оператор autoescape, который используется, чтобы отключить экранирование для большого объема данных. Он может принимать аргументы true или false для включения и отключения экранирования, соответственно. Например:</div><div id="bkmrk--116">  
</div><div id="bkmrk-%7B%25-autoescape-true-%25">{% autoescape true %}</div><div id="bkmrk-%C2%A0-%C2%A0-escaping-enabled"> Escaping enabled</div><div id="bkmrk-%7B%25-endautoescape-%25%7D">{% endautoescape %}</div><div id="bkmrk--117">  
</div><div id="bkmrk-%7B%25-autoescape-false-">{% autoescape false %}</div><div id="bkmrk-%C2%A0-%C2%A0-escaping-disable"> Escaping disabled</div><div id="bkmrk-%7B%25-endautoescape-%25%7D-1">{% endautoescape %}</div><div id="bkmrk--118">  
</div><div id="bkmrk-%D0%92%D1%81%D0%B5-%D0%BC%D0%B5%D0%B6%D0%B4%D1%83-%7B%25-autoesc">Все между {% autoescape false %} и {% endautoescape %} отрендерится без экранирования символов. Если нужно экранировать отдельные символы при выключенном экранировании, стоит использовать фильтр escape. Например:</div><div id="bkmrk--119">  
</div><div id="bkmrk-%7B%25-autoescape-false--1">{% autoescape false %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cdiv-class%3D%22post"> &lt;div class="post"&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-for-post--1"> {% for post in post_list %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Ch2%3E%7B%7B-p-1"> &lt;h2&gt;{{ post.title }}&lt;/h2&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Carticle-1"> &lt;article&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%7B-p-1"> {{ post.html }}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3C%2Farticl-1"> &lt;/article&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D-1"> {% endfor %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3C%2Fdiv%3E-1"> &lt;/div&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cdiv%3E-1"> &lt;div&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-for-comme"> {% for comment in comment_list %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3E%7B%7B-co"> &lt;p&gt;{{ comment|escape }}&lt;/p&gt; # escaping is on for comments</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D-2"> {% endfor %}</div><div id="bkmrk-%C2%A0-%C2%A0-%3C%2Fdiv%3E-2"> &lt;/div&gt;</div><div id="bkmrk-%7B%25-endautoescape-%25%7D-2">{% endautoescape %}</div><div id="bkmrk--120">  
</div><div id="bkmrk-%D0%92%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B">Вложенные шаблоны</div><div id="bkmrk--121">  
</div><div id="bkmrk-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D1%8F-include-%D1%80">Инструкция include рендерит шаблон внутри другого шаблона. Она широко используется, чтобы рендерить статический раздел, который повторяется в разных местах сайта. Вот синтаксис include:</div><div id="bkmrk--122">  
</div><div id="bkmrk-%D0%9F%D1%80%D0%B5%D0%B4%D0%BF%D0%BE%D0%BB%D0%BE%D0%B6%D0%B8%D0%BC%2C-%D1%87%D1%82%D0%BE-%D0%BD%D0%B0%D0%B2">Предположим, что навигационное меню хранится в файле nav.html, сохраненном в папке templates:</div><div id="bkmrk--123">  
</div><div id="bkmrk-%3Cnav%3E">&lt;nav&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ca-href%3D%22%2Fhome%22%3E"> &lt;a href="/home"&gt;Home&lt;/a&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ca-href%3D%22%2Fblog%22%3E"> &lt;a href="/blog"&gt;Blog&lt;/a&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ca-href%3D%22%2Fcontac"> &lt;a href="/contact"&gt;Contact&lt;/a&gt;</div><div id="bkmrk-%3C%2Fnav%3E">&lt;/nav&gt;</div><div id="bkmrk--124">  
</div><div id="bkmrk-%D0%A7%D1%82%D0%BE%D0%B1%D1%8B-%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%B8%D1%82%D1%8C-%D1%8D%D1%82%D0%BE-%D0%BC">Чтобы добавить это меню в home.html, нужно использовать следующий код:</div><div id="bkmrk--125">  
</div><div id="bkmrk-%3C%21doctype-html%3E">&lt;!DOCTYPE html&gt;</div><div id="bkmrk-%3Chtml-lang%3D%22en%22%3E">&lt;html lang="en"&gt;</div><div id="bkmrk-%3Chead%3E">&lt;head&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cmeta-charset%3D%22u"> &lt;meta charset="UTF-8"&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ctitle%3Etitle%3C%2Fti"> &lt;title&gt;Title&lt;/title&gt;</div><div id="bkmrk-%3C%2Fhead%3E">&lt;/head&gt;</div><div id="bkmrk-%3Cbody%3E">&lt;body&gt;</div><div id="bkmrk--126">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%23-%D0%B4%D0%BE%D0%B1%D0%B0%D0%B2%D0%BB%D1%8F%D0%B5%D0%BC-%D0%BF%D0%B0%D0%BD"> {# добавляем панель навигации из nav.html #}</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-include-%27nav."> {% include 'nav.html' %}</div><div id="bkmrk--127">  
</div><div id="bkmrk-%3C%2Fbody%3E">&lt;/body&gt;</div><div id="bkmrk-%3C%2Fhtml%3E">&lt;/html&gt;</div><div id="bkmrk--128">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B2%D0%BE%D0%B4%3A-5">Вывод:</div><div id="bkmrk--129">  
</div><div id="bkmrk-%3C%21doctype-html%3E-1">&lt;!DOCTYPE html&gt;</div><div id="bkmrk-%3Chtml-lang%3D%22en%22%3E-1">&lt;html lang="en"&gt;</div><div id="bkmrk-%3Chead%3E-1">&lt;head&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cmeta-charset%3D%22u-1"> &lt;meta charset="UTF-8"&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ctitle%3Etitle%3C%2Fti-1"> &lt;title&gt;Title&lt;/title&gt;</div><div id="bkmrk-%3C%2Fhead%3E-1">&lt;/head&gt;</div><div id="bkmrk-%3Cbody%3E-1">&lt;body&gt;</div><div id="bkmrk--130">  
</div><div id="bkmrk-%3Cnav%3E-1">&lt;nav&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ca-href%3D%22%2Fhome%22%3E-1"> &lt;a href="/home"&gt;Home&lt;/a&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ca-href%3D%22%2Fblog%22%3E-1"> &lt;a href="/blog"&gt;Blog&lt;/a&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ca-href%3D%22%2Fcontac-1"> &lt;a href="/contact"&gt;Contact&lt;/a&gt;</div><div id="bkmrk-%3C%2Fnav%3E-1">&lt;/nav&gt;</div><div id="bkmrk--131">  
</div><div id="bkmrk-%3C%2Fbody%3E-1">&lt;/body&gt;</div><div id="bkmrk-%3C%2Fhtml%3E-1">&lt;/html&gt;</div><div id="bkmrk--132">  
</div><div id="bkmrk-%D0%9D%D0%B0%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE">Наследование шаблонов</div><div id="bkmrk--133">  
</div><div id="bkmrk-%D0%9D%D0%B0%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE-1">Наследование шаблонов — один из самых мощных элементов шаблонизатора Jinja. Его принцип похож на ООП (объектно-ориентированное программирование). Все начинается с создания базового шаблона, который содержит в себе скелет HTML и отдельные маркеры, которые дочерние шаблоны смогут переопределять. Маркеры создаются с помощью инструкции block. Дочерние шаблоны используют инструкцию extends для наследования или расширения основного шаблона. Вот пример:</div><div id="bkmrk--134">  
</div><div id="bkmrk-%7B%23-%D0%AD%D1%82%D0%BE-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD-templa">{# Это шаблон templates/base.html #}</div><div id="bkmrk-%3C%21doctype-html%3E-2">&lt;!DOCTYPE html&gt;</div><div id="bkmrk-%3Chtml-lang%3D%22en%22%3E-2">&lt;html lang="en"&gt;</div><div id="bkmrk-%3Chead%3E-2">&lt;head&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cmeta-charset%3D%22u-2"> &lt;meta charset="UTF-8"&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ctitle%3E%7B%25-block-"> &lt;title&gt;{% block title %}Default Title{% endblock %}&lt;/title&gt;</div><div id="bkmrk-%3C%2Fhead%3E-2">&lt;/head&gt;</div><div id="bkmrk-%3Cbody%3E-2">&lt;body&gt;</div><div id="bkmrk--135">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-block-nav-%25%7D"> {% block nav %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cul%3E"> &lt;ul&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-h"> &lt;li&gt;&lt;a href="/home"&gt;Home&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-h-1"> &lt;li&gt;&lt;a href="/api"&gt;API&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3C%2Ful%3E-1"> &lt;/ul&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endblock-%25%7D"> {% endblock %}</div><div id="bkmrk-%C2%A0-%C2%A0%C2%A0"> </div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-block-content"> {% block content %}</div><div id="bkmrk-%C2%A0-%C2%A0%C2%A0-1"> </div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endblock-%25%7D-1"> {% endblock %}</div><div id="bkmrk-%3C%2Fbody%3E-2">&lt;/body&gt;</div><div id="bkmrk-%3C%2Fhtml%3E-2">&lt;/html&gt;</div><div id="bkmrk--136">  
</div><div id="bkmrk-%D0%AD%D1%82%D0%BE-%D0%B1%D0%B0%D0%B7%D0%BE%D0%B2%D1%8B%D0%B9-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD-b">Это базовый шаблон base.html. Он создает три блока с помощью block, которые впоследствии будут заполнены дочерними шаблонами. Инструкция block принимает один аргумент — название блока. Внутри шаблона это название должно быть уникальным, иначе возникнет ошибка.</div><div id="bkmrk--137">  
</div><div id="bkmrk-%D0%94%D0%BE%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D0%B9-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD-%E2%80%94-%D1%8D%D1%82">Дочерний шаблон — это шаблон, который растягивает базовый шаблон. Он может добавлять, перезаписывать или оставлять элементы родительского блока. Вот как можно создать дочерний шаблон.</div><div id="bkmrk--138">  
</div><div id="bkmrk-%7B%23-%D0%AD%D1%82%D0%BE-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD-templa-1">{# Это шаблон templates/child.html #}</div><div id="bkmrk-%7B%25-extends-%27base.htm">{% extends 'base.html' %}</div><div id="bkmrk--139">  
</div><div id="bkmrk--140">  
</div><div id="bkmrk-%7B%25-block-content-%25%7D">{% block content %}</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-for-bookmark-"> {% for bookmark in bookmarks %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3E%7B%7B-bookma"> &lt;p&gt;{{ bookmark.title }}&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D-2"> {% endfor %}</div><div id="bkmrk-%7B%25-endblock-%25%7D">{% endblock %}</div><div id="bkmrk--141">  
</div><div id="bkmrk-%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%86%D0%B8%D1%8F-extends-%D1%81">Инструкция extends сообщает Jinja, что child.html — это дочерний элемент, наследник base.html. Когда Jinja обнаруживает инструкцию extends, он загружает базовый шаблон, то есть base.html, а затем заменяет блоки контента внутри родительского шаблона блоками с теми же именами из дочерних шаблонов. Если блок с соответствующим названием не найден, используется блок родительского шаблона.</div><div id="bkmrk--142">  
</div><div id="bkmrk-%D0%A1%D1%82%D0%BE%D0%B8%D1%82-%D0%BE%D1%82%D0%BC%D0%B5%D1%82%D0%B8%D1%82%D1%8C%2C-%D1%87%D1%82%D0%BE-">Стоит отметить, что в дочернем шаблоне перезаписывается только блок content, так что содержимое по умолчанию из title и nav будет использоваться при рендеринге дочернего шаблона. Вывод должен выглядеть следующим образом:</div><div id="bkmrk-%D0%A0%D0%B5%D0%BA%D0%BB%D0%B0%D0%BC%D0%B0-4">Реклама</div><div id="bkmrk--143">  
</div><div id="bkmrk-%3C%21doctype-html%3E-3">&lt;!DOCTYPE html&gt;</div><div id="bkmrk-%3Chead%3E-3">&lt;head&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cmeta-charset%3D%22u-3"> &lt;meta charset="UTF-8"&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ctitle%3Edefault-t"> &lt;title&gt;Default Title&lt;/title&gt;</div><div id="bkmrk-%3C%2Fhead%3E-3">&lt;/head&gt;</div><div id="bkmrk-%3Cbody%3E-3">&lt;body&gt;</div><div id="bkmrk--144">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cul%3E"> &lt;ul&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D"> &lt;li&gt;&lt;a href="/home"&gt;Home&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D-1"> &lt;li&gt;&lt;a href="/api"&gt;API&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3C%2Ful%3E"> &lt;/ul&gt;</div><div id="bkmrk--145">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl"> &lt;p&gt;Bookmark title 1&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl-1"> &lt;p&gt;Bookmark title 2&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl-2"> &lt;p&gt;Bookmark title 3&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl-3"> &lt;p&gt;Bookmark title 4&lt;/p&gt;</div><div id="bkmrk--146">  
</div><div id="bkmrk--147">  
</div><div id="bkmrk-%3C%2Fbody%3E-3">&lt;/body&gt;</div><div id="bkmrk-%3C%2Fhtml%3E-3">&lt;/html&gt;</div><div id="bkmrk--148">  
</div><div id="bkmrk-%D0%95%D1%81%D0%BB%D0%B8-%D0%BD%D1%83%D0%B6%D0%BD%D0%BE%2C-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE-%D0%BF%D0%BE">Если нужно, можно поменять заголовок по умолчанию, переписав блок title в child.html:</div><div id="bkmrk--149">  
</div><div id="bkmrk-%7B%23-%D0%AD%D1%82%D0%BE-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD-templa-2">{# Это шаблон templates/child.html #}</div><div id="bkmrk-%7B%25-extends-%27base.htm-1">{% extends 'base.html' %}</div><div id="bkmrk--150">  
</div><div id="bkmrk-%7B%25-block-title-%25%7D">{% block title %}</div><div id="bkmrk-%C2%A0-%C2%A0-child-title"> Child Title</div><div id="bkmrk-%7B%25-endblock-%25%7D-1">{% endblock %}</div><div id="bkmrk--151">  
</div><div id="bkmrk-%7B%25-block-content-%25%7D-1">{% block content %}</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-for-bookmark--1"> {% for bookmark in bookmarks %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3E%7B%7B-bookma-1"> &lt;p&gt;{{ bookmark.title }}&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D-3"> {% endfor %}</div><div id="bkmrk-%7B%25-endblock-%25%7D-2">{% endblock %}</div><div id="bkmrk--152">  
</div><div id="bkmrk-%D0%9F%D0%BE%D1%81%D0%BB%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D0%B8-%D0%B1%D0%BB%D0%BE">После перезаписи блока на контент из родительского шаблона все еще можно ссылаться с помощью функции super(). Обычно она используется, когда в дополнение к контенту дочернего шаблона нужно добавить содержимое из родительского. Например:</div><div id="bkmrk--153">  
</div><div id="bkmrk-%7B%23-%D0%AD%D1%82%D0%BE-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD-templa-3">{# Это шаблон templates/child.html #}</div><div id="bkmrk-%7B%25-extends-%27base.htm-2">{% extends 'base.html' %}</div><div id="bkmrk--154">  
</div><div id="bkmrk-%7B%25-block-title-%25%7D-1">{% block title %}</div><div id="bkmrk-%C2%A0-%C2%A0-child-title-1"> Child Title</div><div id="bkmrk-%7B%25-endblock-%25%7D-3">{% endblock %}</div><div id="bkmrk--155">  
</div><div id="bkmrk-%7B%25-block-nav-%25%7D">{% block nav %}</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%7B-super%28%29-%7D%7D-%7B%23"> {{ super() }} {# referring to the content in the parent templates #}</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D%22%2Fco"> &lt;li&gt;&lt;a href="/contact"&gt;Contact&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D%22%2Fca"> &lt;li&gt;&lt;a href="/career"&gt;Career&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%7B%25-endblock-%25%7D-4">{% endblock %}</div><div id="bkmrk--156">  
</div><div id="bkmrk-%7B%25-block-content-%25%7D-2">{% block content %}</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-for-bookmark--2"> {% for bookmark in bookmarks %}</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cp%3E%7B%7B-bookma-2"> &lt;p&gt;{{ bookmark.title }}&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%7B%25-endfor-%25%7D-4"> {% endfor %}</div><div id="bkmrk-%7B%25-endblock-%25%7D-5">{% endblock %}</div><div id="bkmrk--157">  
</div><div id="bkmrk-%D0%92%D1%8B%D0%B2%D0%BE%D0%B4%3A-6">Вывод:</div><div id="bkmrk--158">  
</div><div id="bkmrk-%3C%21doctype-html%3E-4">&lt;!DOCTYPE html&gt;</div><div id="bkmrk-%3Chead%3E-4">&lt;head&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cmeta-charset%3D%22u-4"> &lt;meta charset="UTF-8"&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Ctitle%3Echild-tit"> &lt;title&gt;Child Title&lt;/title&gt;</div><div id="bkmrk-%3C%2Fhead%3E-4">&lt;/head&gt;</div><div id="bkmrk-%3Cbody%3E-4">&lt;body&gt;</div><div id="bkmrk--159">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cul%3E-1"> &lt;ul&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D-2"> &lt;li&gt;&lt;a href="/home"&gt;Home&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D-3"> &lt;li&gt;&lt;a href="/api"&gt;API&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D-4"> &lt;li&gt;&lt;a href="/contact"&gt;Contact&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%C2%A0-%C2%A0-%3Cli%3E%3Ca-href%3D-5"> &lt;li&gt;&lt;a href="/career"&gt;Career&lt;/a&gt;&lt;/li&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3C%2Ful%3E-1"> &lt;/ul&gt;</div><div id="bkmrk--160">  
</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl-4"> &lt;p&gt;Bookmark title 1&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl-5"> &lt;p&gt;Bookmark title 2&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl-6"> &lt;p&gt;Bookmark title 3&lt;/p&gt;</div><div id="bkmrk-%C2%A0-%C2%A0-%3Cp%3Ebookmark-titl-7"> &lt;p&gt;Bookmark title 4&lt;/p&gt;</div><div id="bkmrk--161">  
</div><div id="bkmrk--162">  
</div><div id="bkmrk-%3C%2Fbody%3E-4">&lt;/body&gt;</div><div id="bkmrk-%3C%2Fhtml%3E-4">&lt;/html&gt;</div></body></html>

# Авторизация и аутентификация

**Ссылки:**

[Fastapi users документация](https://fastapi-users.github.io/fastapi-users/latest/)

[Role-based authentification](https://app-generator.dev/docs/technologies/fastapi/rbac.html)

**Подготовка проекта**

```
python -m venv --system-site-packages env
python -m pip install fastapi uvicorn
```