ENote
  • ✨Home
    • Відмова від відповідальності
  • Progr
    • Python
      • Модулі
        • pip
        • cgitb
        • datetime
          • Класс datetime() модуля datetime
            • Методы объекта datetime.datetime()
            • datetime.datetime examples
          • Класс timedelta() модуля datetime
            • datetime.timedelta examples
          • Класс date() модуля datetime
            • datetime.date examples
          • Класс time() модуля datetime
            • Формат для функций .strftime() и .strptime(). модуля datetime
        • os.path
        • pathlib
          • pathlib to str
        • subproces
        • os
        • Jinja
          • Синтаксис шаблонів Jinja
          • Клас Environment()
          • Простой пример cgi-скрипта c Jinja-шаблоном
          • Создание переменных
            • Як оновити глобальну змінну зсередини оператора IF / ELSE або циклу FOR
          • Фільтри і методи
          • Число у рядок, slices
          • Вбудовані фільтри Jinja2
        • re
          • re.search - example
          • re.findall - example
        • email / smtplib
          • Как отправлять электронные письма с помощью Python
        • requests
          • Як зберегти та завантажити файли cookie в запитах Python?
          • Извлечение и установка cookies с модулем requests в Python
          • Links
        • http.cookies
          • Всё о работе с cookie в Python — класс http.cookies
        • xlrd
        • xlwt
        • borb
          • ChunkOfText
          • send_usage_statistics
          • borb clear
          • 2.1.3 vs 2.1.15
          • QR-code
          • Залежності borb
        • JSON
          • Кирилиця в JSON
        • matplotlib
        • argparse
        • click
        • configparser
        • traceback
        • sys
          • exit()
        • mysql-connector-python
        • logging
        • icrawler
        • Auto Plates
        • rembg
        • random
      • Strings
        • Built-in methods
        • Форматування виводу
        • Початкові нулі
        • Рядок в число
      • list
        • Об’єднання списків
        • list.sort(), sorted()
        • list.reverse(), reversed()
        • all(), any()
        • sum(), min(), max()
        • map(), filter(), reduce()
        • join(), split()
      • tuple
      • dict
        • Об'єднання / злиття словників
        • Сортування словника Python: значення, ключі тощо
      • set
      • class Enum
      • Середнє арифметичне
      • Virtual environment
        • web-app
      • type(), isinstance()
      • __main__
      • Files & Dirs
        • Try except for exception handling
        • Cписок файлов директории
        • User Home Dir
        • Copy file
      • *args, **qwargs
      • Links
      • Область видимости
      • Handling a File Error
      • assert
      • if
      • Числа
        • Округлення чисел
        • Отримати число з рядка
      • Обработка исключений в Python
      • Файлы и сериализация данных
      • OOP
      • Net and Web
      • Структура проекта на Python
      • Распаковка итерируемых объектов
      • Links
      • Algorithms
      • Python exit commands: quit(), exit(), sys.exit() and os._exit()
      • Цикли for / while
      • uuid
    • JavaScript
      • String
        • replaceAll() polyfill
        • Шаблонные строки
      • Array
        • Все способы перебора массива в JavaScript
      • Object
      • document.location
      • RegExp
      • Examples
        • Вычисление остатка от деления
        • Остаток от деления и деление без остатка
        • Округление числа
      • XMLHttpRequest
      • alert, prompt, confirm
      • onclick
      • hidden, display:none
      • LocalStorage, sessionStorage
      • null, undefined
      • cookies (js)
      • var, let и const
        • var vs let
        • const
      • Модифікація DOM
        • DOM select
      • JSON
        • Try
      • fetch
      • typeof
      • FormData не включає disabled набори полів
      • FormData, fdata
      • Більше одного відео YouTube на одній сторінці
    • HTML, CSS
      • favicon
      • Деякі спецсимволи
      • meta
      • ASCII table
      • lang
      • Псевдоелементи ::after і ::before
      • Cursor
      • Об использовании нестандартных пробелов
      • Картинка фоном
      • Безпечні веб-шрифти
      • Завжди внизу, незалежно від пропорцій екрану
      • напівпрозорий елемент
      • Символи з тінью
      • SVG (bootstrap)
      • rel = canonical
      • link stylesheet: integrity & crossorigin
      • rel = noopener
    • Bootstrap
      • Form Validate
      • Password show/hide
    • Errors
  • Dev
    • Git
      • clone
      • git-scm (book)
      • git config
        • files .git*
        • core.filemode
        • core.sharedRepository
      • .gitignore
      • .gitkeep
      • Видалити з репозиторію
        • Видалений файл з однієї гілки...
      • Пам’ятка
        • Перегляд історії комітів
        • Скасувати git add
        • revert
        • Скасувати внесені зміни у файл
        • Додати до коміту файл
        • Видалити історію попередніх коммітів, та почати "з нуля"
        • Додати файли в останній коміт
      • Робота з гілками
        • Порівняти гілки
      • Git за полчаса
      • Три розділи проєкту Git
      • Merge conflict
      • Pull error
        • Git Error: You have divergent branches...
      • diff
      • Video
      • Merge скасувати
      • .gitignore: Permission denied
    • GitHub
      • SSH-підключення до GitHub
      • Перенести на сервер локальный репозиторий
      • Перенести на сервер репозиторій разом з історією
      • Створення змісту
    • Security
      • robots.txt
      • Cookies
    • Аутентифікація і cookies
      • ChatGPT
  • data
    • MySQL
      • MyISAM vs InnoDB
      • Типи даних
        • NULL (todo)
        • TIMESTAMP
        • YEAR
        • JSON
        • Требования к памяти для символьных типов
        • Поиск записей в таблице, которым нет соответствия в другой
      • Приклад створення БД, та користувача
        • Права для пользователей
      • Переглянути всі індекси таблиці
      • Копіювання, клонування таблиць
      • TEMPORARY TABLE
      • JOIN
      • ALTER TABLE
      • AUTO_INCREMENT
        • AUTO_INCREMENT у складовому індексі
      • LIMIT
        • Использование MySQL LIMIT
      • 10 Примеров входной загрузки данных из текстового файла в таблицы MySQL
      • Рішення
        • Выявление и удаление несвязанных записей
        • Выборка произвольных записей
        • Коректне сортування українських літер
        • Найти записи, которые присутствуют в одной таблице и отсутствуют во второй
        • Как удобно посмотреть данные...
        • Нахождение "дыр" в нумерации
        • Знайти дубликати полів в одній таблиці
        • Дані колонки 1 табл. перенести в 2 табл.
      • Функції
        • LAST_INSERT_ID()
        • GROUP_CONCAT
        • COUNT + DISTINCT
        • Функции для работы с датами и временем
      • Автоматизируйте создание бэкапов
      • mysqldump
        • Time Zone UTC
      • Результат запиту у файл
      • Результат запиту у змінну
      • Пособие по MySQL на Python
      • Змінні
      • Эмуляция функции row_number() в MySQL
      • Изучаем хранимые процедуры MySQL
      • SELECT DISTINCT
      • Dump всієї бази даних
      • Індекси
      • FOREIGN KEY
      • MAX(), MIN()
      • LENGTH, CHAR_LENGTH
      • Встановлення
    • MariaDB
    • PostgreSQL
      • Работа с базой данных PostgreSQL
      • Работаем с PostgreSQL через командную строку в Linux
    • Domains
      • Життєвий цикл доменів
      • Статус домена
    • SQLite, MySQL и PostgreSQL: сравниваем популярные реляционные СУБД
  • Linux
    • DNS
      • Как в DNS прописать 301 редирект
      • mail
        • SPF
          • Mirohost
        • _dmarc _domainkey
        • DKIM
        • Прописати ключі DKIM в exim
        • Листи з неіснуючим адресатом
    • Server
      • Zomro
        • pip
        • SSH-доступ по ключу (zomro)
        • venv
        • UnicodeEncodeError: 'latin-1' codec can't encode character
        • Mail Ports
        • Редірект з SSL-сертификатом на транзитному сайті
        • Редірект з SSL за допомогою .htaccess
      • Створення нового користувача з привілеями sudo в Ubuntu
      • SSH-доступ по ключу
      • Часовий пояс в Ubuntu 20.04
      • SSH-підключення командний рядок
      • Як встановити Python 3.9 (нижчу) на Ubuntu 22.04
      • Автозагрузка сервисов в Ubuntu
      • Підвищення безпеки SSH
      • Ubuntu Server
        • Art 01
    • Commands
      • adduser
      • apt
      • cat
      • ls
      • tar
      • ln
      • find
      • chmod
      • chown
      • mv
      • dig
      • ping
      • passwd
      • htpasswd
      • umask
      • usermode
      • history
      • cmp
      • chattr +i
    • Config
      • Keyboard
      • windows
      • My kbdswtch
      • Затримка при завантаженні системи
      • Files
        • /etc/resolv.conf
        • /boot/grub/grub.cfg
        • .config/user-dir.dirs
        • /etc/fstab
      • Як встановити шрифти
    • Apache
      • Встановлення
      • Подключить виртуальный хост
      • Файл .htaccess
        • Установка индексного файла
        • Фільтр IP-адрес
        • ModRewrite
          • Заборонити доступ за User-Agent
          • Перенаправити на іншу сторінку
          • Додавати слеш до адреси
        • Включити SSI
        • Виконувати скрипти CGI
        • Тимчасовий перехід з одного домену на інший
      • SSI
      • SSL
      • Відключити старт Apache з системою
      • Помилки
        • Скрипт не працює
        • CGI-скрипт не виводить кирилицю
        • Could not reliably determine
        • Permissions are missing on a component of the path
        • Symbolic link not allowed or link target not accessible
      • AddType, AddLanguage, AddCharset
    • Nginx
      • 301 редирект з www. та http: на https://(без www.)domain
    • Soft
      • SublimeText
        • Plugins
      • Firefox
      • Gwenview
      • inkscape
      • Double Commander
      • nano
      • mc
        • Знайти потрібний файл
      • meld / diffuse
      • hexedit
      • Kazam - відео з екрану
      • VeraCrypt
      • XnView MP
      • LibreOffice
      • xdotool
      • System Load Monitor
      • Battery Monitor
      • qBittorrent
    • Перетворення .RPM в .DEB
    • Bash
      • Конкатенация строк в Bash
      • Page
    • Файлові часові позначки в Linux: atime, mtime, ctime
    • Права доступу для файлів і каталогів
    • Зміна паролю root
    • Быстро удалить огромное количество файлов в каталоге
    • Як узнати версію Linux?
    • USB Flash ext4
    • Clear Cache
    • Доступ до спільної папки на Windows
    • Віртуальні консолі TTY1–TTY6
    • APT. Заборона оновлення
  • Різне
    • GitBook
    • Банковское округление
    • Ім’я користувача Youtube
  • Hard
    • Hardware
      • Acer Extensa
      • Таймер Feron TM22
      • WD My Book World Edition 2Tb
        • FTP
        • SSH
          • Проблеми
        • SSHFS
      • Canon PIXMA E3340
      • Термометри
    • Auto
      • Акумулятор
    • Electro
    • USB Flash recovery
Powered by GitBook
On this page
  • Install
  • Почему Jinja2?
  • Пример использования Jinja2
  • Hello name!
  • Комментарии
  • Операторы
  • Модули
  • Макросы
  • Чтение из файла
  • Окружение (Environment)
  • Настройки
  • Загрузчики шаблонов (Loaders)
  • Шаблон конфига Nginx
  • Блог
  • Links
  1. Progr
  2. Python
  3. Модулі

Jinja

PreviousosNextСинтаксис шаблонів Jinja

Last updated 2 years ago

Довжина списку словників, та обробка його обробка:

{% if EQU_TYPES_LIST|length > 0 %}
{%- for dict in EQU_TYPES_LIST %}
<div class="col py-3">
	<h5 class="card-title">{{ dict.typ_mark }}</h5>
	<p>{{ dict.typ_name }}</p>
</div>
{% endfor -%}

Install

pip3 install Jinja2
Successfully installed Jinja2-2.11.2 MarkupSafe-1.1.1" %}

На сервере, где установлено окружение (напр. python3.7), необходимо добавить опцию --user:

which pip3.7
/usr/local/bin/pip3.7
pip3.7 install Jinja2"
Could not install packages due to an EnvironmentError: [Errno 13] Permission denied...
Consider using the `--user` option or check the permissions." %}
pip3.7 install --user Jinja2"
Installing collected packages: MarkupSafe, Jinja2
Successfully installed Jinja2-2.11.2 MarkupSafe-1.1.1" %}

Почему Jinja2?

http://python2or3.blogspot.com/2015/08/python.html

Если по вопросу "с какого фреймворка начинать в Питоне" еще есть плюрализм (от "Flask - он легковесный, наращиваешь сам и понимаешь как все работает" до "Django - в нем все есть, а чего нет, быстро доустанавливаешь"), то с шаблонизаторами все упростилось.

До недавнего времени шаблонизаторов было 3-4: Jinja, Mako, Genshi и, конечно, Django Templates.

Собственно, они никуда не делись, Genshi и сейчас используется по умолчанию в Turbogears 2, а Mako - в Pylons/Pyramid.

Но и Turbogears, и Django и Pyramid с недавнего времени поддерживают шаблонизатор, ставший популярным благодаря Flask - Jinja 2.

Ну и, наконец, посмтрим на подборку генераторов статических сайтов (http://www.staticgen.com/): 11 из 17, в том числе самый популярный Pelican (http://docs.getpelican.com/) опираются на Jinja2.

Итого - вопрос с выбором шаблонизатора Python на сегодня не стоит.

Пример использования Jinja2

https://lectureswww.readthedocs.io/6.www.sync/2.codding/3.templates/jinja2.html

Hello name!

# -*- coding: utf-8 -*-
from jinja2 import Template

template = Template('Hello ![pic]( name )!')
print(template.render(name=u'Вася'))

Hello Вася!

Комментарии

{# Это кусок кода, который временно не нужен, но удалять жалко
    {% for user in users %}
        ...
    {% endfor %}
#}

Операторы

См.также https://ru.wikipedia.org/wiki/Оператор_(программирование)

from jinja2 import Template
text = '{% for item in range(5) %}Hello ![pic]( name )! {% endfor %}'
template = Template(text)
print(template.render(name=u'Вася'))

Hello Вася! Hello Вася! Hello Вася! Hello Вася! Hello Вася!

Модули

from jinja2 import Template
template = Template("{% set a, b, c = 'foo', 'фуу', 'föö' %}")
m = template.module
print(m.a)
print(m.b)
print(m.c)

foo фуу föö

Макросы

from jinja2 import Template

template = Template('{% macro foo() %}42{% endmacro %}23')
m = template.module
print(m)
print(m.foo())

23 42

Чтение из файла

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    {% for item in range(5) %}
      Hello ![pic]( name )!
    {% endfor %}
  </body>
</html>

jinja2/3.loader/0.file.py — чтение шаблона из файла

from jinja2 import Template

html = open('foopkg/templates/0.hello.html').read()
template = Template(html)
print(template.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>

      Hello Петя!

      Hello Петя!

      Hello Петя!

      Hello Петя!

      Hello Петя!

  </body>
</html>

Окружение (Environment)

См.также

http://jinja.pocoo.org/docs/dev/api/#loaders

http://jinja.pocoo.org/docs/dev/api/#jinja2.Environment

Настройки

Загрузчики шаблонов (Loaders)

FileSystemLoader

# -*- coding: utf-8 -*-
from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('foopkg/templates'))
template = env.get_template('0.hello.html')
print(template.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

PackageLoader

from jinja2 import Environment, DictLoader

html = '''<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    {% for item in range(5) %}
      Hello ![pic]( name )!
    {% endfor %}
  </body>
</html>
'''

env = Environment(loader=DictLoader({'index.html': html}))
template = env.get_template('index.html')
print(template.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

DictLoader

# -*- coding: utf-8 -*-
from jinja2 import Environment, DictLoader

html = '''<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    

<div data-gb-custom-block data-tag="for" data-0='5' data-1='5' data-2='5' data-3='5' data-4='5' data-5='5' data-6='5' data-7='5' data-8='5' data-9='5' data-10='5' data-11='5' data-12='5' data-13='5' data-14='5'>

      Hello ![pic]( name )!
    

</div>

  </body>
</html>
'''

env = Environment(loader=DictLoader({'index.html': html}))
template = env.get_template('index.html')
print(template.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

FunctionLoader

from jinja2 import Environment, FunctionLoader

html = '''<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    {% for item in range(5) %}
      Hello ![pic]( name )!
    {% endfor %}
  </body>
</html>
'''


def myloader(name):
    if name ### 'index.html':
        return html

env = Environment(loader=FunctionLoader(myloader))
template = env.get_template('index.html')
print(template.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

PrefixLoader

from jinja2 import Environment, FunctionLoader, PackageLoader, PrefixLoader

html = '''<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    {% for item in range(5) %}
      Hello ![pic]( name )!
    {% endfor %}
  </body>
</html>
'''

def myloader(name):
    if name ### 'index.html':
        return html

env = Environment(loader=PrefixLoader({
    'foo': FunctionLoader(myloader),
    'bar': PackageLoader('foopkg', 'templates')
}))
template1 = env.get_template('foo/index.html')
template2 = env.get_template('bar/0.hello.html')
print(template1.render(name=u'Петя'))
print(template2.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

ChoiceLoader

from jinja2 import Environment, FunctionLoader, PackageLoader, ChoiceLoader

html = '''<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  </head>
  <body>
    {% for item in range(5) %}
      Hello ![pic]( name )!
    {% endfor %}
  </body>
</html>
'''


def myloader(name):
    if name ### 'index.html':
        return html

env = Environment(loader=ChoiceLoader({
    FunctionLoader(myloader),
    PackageLoader('foopkg', 'templates')
}))
template1 = env.get_template('index.html')
template2 = env.get_template('0.hello.html')
print(template1.render(name=u'Петя'))
print(template2.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

ModuleLoader

# -*- coding: utf-8 -*-
from jinja2 import Environment, FileSystemLoader, ModuleLoader

# Compile template
Environment(loader=FileSystemLoader('foopkg/templates'))\
    .compile_templates("foopkg/compiled/foopkg.zip",
                       py_compile=True)  # pyc generate, only for python2

# Environment
env = Environment(loader=ModuleLoader("foopkg/compiled/foopkg.zip"))
template = env.get_template('0.hello.html')
print(template.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

BaseLoader

# -*- coding: utf-8 -*-
from os.path import exists, getmtime, join

from jinja2 import BaseLoader, Environment, TemplateNotFound


class FoopkgLoader(BaseLoader):

    def __init__(self, path="foopkg/templates"):
        self.path = path

    def get_source(self, environment, template):
        path = join(self.path, template)
        if not exists(path):
            raise TemplateNotFound(template)
        mtime = getmtime(path)
        with open(path) as f:
            source = f.read()
        return source, path, lambda: mtime ### getmtime(path)

# Environment
env = Environment(loader=FoopkgLoader())
template = env.get_template('0.hello.html')
print(template.render(name=u'Петя'))

Результат рендеринга шаблона jinja2/3.loader/foopkg/templates/0.hello.html

Шаблон конфига Nginx

server {
         listen ![pic]( SRC_SERVER_PUB_IP ):80;
         servern_name ![pic]( FQDN }} www.{{ FQDN )

          location / {
              proxy_pass         http://![pic]( SRC_SERVER_LOCAL_IP ):80/;
              proxy_redirect     off;

              proxy_set_header   Host             $host;
              proxy_set_header   X-Real-IP        $remote_addr;
              proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
         }
}
#!/usr/bin/env python
from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('.'))

template = env.get_template('nginx_proxy_conf.tpl')

data = {
    "SRC_SERVER_PUB_IP": "192.168.0.100",
    "SRC_SERVER_LOCAL_IP": "10.0.3.100",
    "FQDN": "example.com"
}

conf = template.render(**data)
print(conf)

open("proxy.nginx.conf", "w").write(conf)
server {
         listen 192.168.0.100:80;
         servern_name example.com www.example.com

          location / {
              proxy_pass         http://10.0.3.100:80/;
              proxy_redirect     off;

              proxy_set_header   Host             $host;
              proxy_set_header   X-Real-IP        $remote_addr;
              proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
         }
}

<!DOCTYPE html>
<html lang="en">
<head>
    

<div data-gb-custom-block data-tag="block">

      <link rel="stylesheet" href="style.css" />
      <title>

<div data-gb-custom-block data-tag="block"></div> - My Webpage</title>
      <meta charset='utf-8'>
    </div>

</head>
<body>
    <div id="content">

<div data-gb-custom-block data-tag="block"></div></div>
    <div id="footer">
        <div data-gb-custom-block data-tag="block">

          &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.
        

</div>

    </div>
</body>
</html>

<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>

<div data-gb-custom-block data-tag="block">Index</div>

<div data-gb-custom-block data-tag="block">

    ![pic]( super() )
    <style type="text/css">
        .important { color: #336699; }
    </style>

</div>

<div data-gb-custom-block data-tag="block">

    <h1>Index</h1>
    <p class="important">
      Welcome ![pic]( name ) to my awesome homepage.
    </p>

</div>
# -*- coding: utf-8 -*-
from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('index.html')
print(template.render(name=u'Петя'))
<!DOCTYPE html>
<html lang="en">
<head>


    <link rel="stylesheet" href="style.css" />
    <title>Index — My Webpage</title>
    <meta charset='utf-8'>

    <style type="text/css">
        .important { color: #336699; }
    </style>

</head>
<body>
    <div id="content">
    <h1>Index</h1>
    <p class="important">
      Welcome Петя to my awesome homepage.
    </p>
</div>
    <div id="footer">

        &copy; Copyright 2008 by <a href="http://domain.invalid/">you</a>.

    </div>
</body>
</html>

Блог

templates/base.html — базовый шаблон.

<!DOCTYPE html>
<html lang="en">
<head>
    

<div data-gb-custom-block data-tag="block">

      <link rel="stylesheet" href="style.css" />
      <title>

<div data-gb-custom-block data-tag="block"></div> - My Blog</title>
      <meta charset='utf-8'>
    </div>

</head>
<body>
    <div id="content">

<div data-gb-custom-block data-tag="block"></div></div>
    <br />
    <br />
    <br />
    <div id="footer">
        <div data-gb-custom-block data-tag="block">

          &copy; Copyright 2015 by <a href="http://domain.invalid/">you</a>.
        

</div>

    </div>
</body>
</html>

Главная страница templates/index.html наследуется от templates/base.html


<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>

<div data-gb-custom-block data-tag="block">Index</div>

<div data-gb-custom-block data-tag="block">

    <h1>Simple Blog</h1>
    <a href="/article/add">Add article</a>
    <br />
    <br />
    

<div data-gb-custom-block data-tag="for">

      ![pic]( article.id }} - (<a href="/article/{{ article.id )/delete">delete</a> |
      <a href="/article/![pic]( article.id )/edit">edit</a>)
      <a href="/article/![pic]( article.id }}">{{ article.title )</a><br />
    

</div>

</div>

templates/create.html наследуется от базового шаблона.


<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>

<div data-gb-custom-block data-tag="block">Create</div>

<div data-gb-custom-block data-tag="block">

    <h1>Simple Blog -> EDIT</h1>
    <form action="" method="POST">
        Title:<br>
        <input type="text" name="title" value="![pic]( article.title )"><br>
        Content:<br>
        <textarea name="content">![pic]( article.content )</textarea><br><br>
        <input type="submit" value="Submit">
    </form>

</div>

templates/read.html наследуется от базового шаблона.


<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>

<div data-gb-custom-block data-tag="block">Index</div>

<div data-gb-custom-block data-tag="block">

    <h1><a href="/">Simple Blog</a> -> READ</h1>
    <h2>![pic]( article.title )</h2>
    ![pic](  article.content )

</div>

views.py — окружение Jinja2.

from models import ARTICLES

from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('templates'))


class BaseBlog(object):

    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response


class BaseArticle(BaseBlog):

    def __init__(self, *args):
        super(BaseArticle, self).__init__(*args)
        article_id = self.environ['wsgiorg.routing_args'][1]['id']
        (self.index,
         self.article) = next(((i, art) for i, art in enumerate(ARTICLES)
                               if art['id'] ### int(article_id)),
                              (None, None))


class BlogIndex(BaseBlog):

    def __iter__(self):
        self.start('200 OK', [('Content-Type', 'text/html')])
        yield str.encode(
            env.get_template('index.html').render(articles=ARTICLES)
        )


class BlogCreate(BaseBlog):

    def __iter__(self):
        if self.environ['REQUEST_METHOD'].upper() ### 'POST':
            from urllib.parse import parse_qs
            values = parse_qs(self.environ['wsgi.input'].read())
            max_id = max([art['id'] for art in ARTICLES])
            ARTICLES.append(
                {'id': max_id+1,
                 'title': values[b'title'].pop().decode(),
                 'content': values[b'content'].pop().decode()
                 }
            )
            self.start('302 Found',
                       [('Content-Type', 'text/html'),
                        ('Location', '/')])
            return

        self.start('200 OK', [('Content-Type', 'text/html')])
        yield str.encode(
            env.get_template('create.html').render(article=None)
        )


class BlogRead(BaseArticle):

    def __iter__(self):
        if not self.article:
            self.start('404 Not Found', [('content-type', 'text/plain')])
            yield b'not found'
            return

        self.start('200 OK', [('Content-Type', 'text/html')])
        yield str.encode(
            env.get_template('read.html').render(article=self.article)
        )


class BlogUpdate(BaseArticle):

    def __iter__(self):
        if self.environ['REQUEST_METHOD'].upper() ### 'POST':
            from urllib.parse import parse_qs
            values = parse_qs(self.environ['wsgi.input'].read())
            self.article['title'] = values[b'title'].pop().decode()
            self.article['content'] = values[b'content'].pop().decode()
            self.start('302 Found',
                       [('Content-Type', 'text/html'),
                        ('Location', '/')])
            return
        self.start('200 OK', [('Content-Type', 'text/html')])
        yield str.encode(
            env.get_template('create.html').render(article=self.article)
        )


class BlogDelete(BaseArticle):

    def __iter__(self):
        self.start('302 Found',  # '301 Moved Permanently',
                   [('Content-Type', 'text/html'),
                    ('Location', '/')])
        ARTICLES.pop(self.index)
        yield b''

Links

  • https://eax.me/python-jinja/Работа с HTML-шаблонами в Python при помощи Jinja

Экспериментальная поддержка Python 3 :nbsp: Jinja 2.7 обеспечивает экспериментальную поддержку Python >= 3.3. Это означает, что все unittests передают новую версию, но там могут быть небольшие ошибки, и поведение может быть непоследовательным. Если вы заметили какие-либо ошибки, сообщите об этом в трекер Jinja.

:gb:

:gb:

(есть в wiki)

⚠️
❗
Простой пример cgi-скрипта подключающего шаблон Jinja
https://docs-python.ru/packages/modul-jinja2-python/
Templating With Jinja2 in Flask: Essentials
Templating With Jinja2 in Flask: Date and Time Formatting With moment.js
https://lectureswww.readthedocs.io/6.www.sync/2.codding/3.templates/jinja2.html
Jinja + Flask
Jinja2 Templating Engine Tutorial