HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p><strong>Рассказываем про один из самых популярных и лаконичных микрофреймворков для Python - Flask. Как написать простое приложение, подключить к нему Bootstrap и базу данных, и есть ли вообще у Flask минусы.</strong></p>
1 <p><strong>Рассказываем про один из самых популярных и лаконичных микрофреймворков для Python - Flask. Как написать простое приложение, подключить к нему Bootstrap и базу данных, и есть ли вообще у Flask минусы.</strong></p>
2 <p>Flask - это микрофреймворк для создания веб-приложений на Python. В нем из коробки доступен только минимальный инструментарий, но при этом он поддерживает расширения так, как будто они реализованы в самом Flask. Расширения для микрофреймворка позволяют коммуницировать с базами данных, проверять формы, контролировать загрузку на сервер, работать с аутентификацией и многое другое.</p>
2 <p>Flask - это микрофреймворк для создания веб-приложений на Python. В нем из коробки доступен только минимальный инструментарий, но при этом он поддерживает расширения так, как будто они реализованы в самом Flask. Расширения для микрофреймворка позволяют коммуницировать с базами данных, проверять формы, контролировать загрузку на сервер, работать с аутентификацией и многое другое.</p>
3 <p>Первая публичная версия Flask вышла 16 апреля 2010 года. Автор проекта -<a>Армин Ронахер</a>, который возглавлял команду энтузиастов в Python-разработке Poocco. Flask основан на быстром и расширяемом механизме шаблонов Jinja и наборе инструментов Werkzeug. Кроме того, Flask использует одну из самых передовых служебных библиотек WSGI (Web Server Gateway Interface - стандарт взаимодействия между Python-программой, выполняющейся на стороне сервера, и самим веб-сервером).</p>
3 <p>Первая публичная версия Flask вышла 16 апреля 2010 года. Автор проекта -<a>Армин Ронахер</a>, который возглавлял команду энтузиастов в Python-разработке Poocco. Flask основан на быстром и расширяемом механизме шаблонов Jinja и наборе инструментов Werkzeug. Кроме того, Flask использует одну из самых передовых служебных библиотек WSGI (Web Server Gateway Interface - стандарт взаимодействия между Python-программой, выполняющейся на стороне сервера, и самим веб-сервером).</p>
4 <p>При этом WSGI тоже разработал Армин Ронахер. По его словам, идея Flask изначально была первоапрельской шуткой, которая стала популярной и превратилась в серьезное приложение.</p>
4 <p>При этом WSGI тоже разработал Армин Ронахер. По его словам, идея Flask изначально была первоапрельской шуткой, которая стала популярной и превратилась в серьезное приложение.</p>
5 <blockquote><h3>Изучите Python на Хекслете</h3>
5 <blockquote><h3>Изучите Python на Хекслете</h3>
6 <p>Пройдите нашу профессию "<a>Python-разработчик</a>", чтобы поменять свою жизнь и стать бэкенд-программистом.</p>
6 <p>Пройдите нашу профессию "<a>Python-разработчик</a>", чтобы поменять свою жизнь и стать бэкенд-программистом.</p>
7 </blockquote><h2>Содержание</h2>
7 </blockquote><h2>Содержание</h2>
8 <ul><li><a>Плюсы и минусы Flask</a></li>
8 <ul><li><a>Плюсы и минусы Flask</a></li>
9 <li><a>Как создать проект на Flask</a></li>
9 <li><a>Как создать проект на Flask</a></li>
10 <li><a>Структура приложения на Flask</a></li>
10 <li><a>Структура приложения на Flask</a></li>
11 <li><a>Подключаем Bootstrap</a></li>
11 <li><a>Подключаем Bootstrap</a></li>
12 <li><a>Подключаем базу данных</a></li>
12 <li><a>Подключаем базу данных</a></li>
13 <li><a>Что еще почитать про Flask</a></li>
13 <li><a>Что еще почитать про Flask</a></li>
14 </ul><h2>Плюсы и минусы Flask</h2>
14 </ul><h2>Плюсы и минусы Flask</h2>
15 <p>Практически все плюсы и минусы Flask появились именно из-за того, что он является микрофреймворком.</p>
15 <p>Практически все плюсы и минусы Flask появились именно из-за того, что он является микрофреймворком.</p>
16 <p>Среди достоинств:</p>
16 <p>Среди достоинств:</p>
17 <ul><li><strong>Простота.</strong>Flask легко установить и настроить.</li>
17 <ul><li><strong>Простота.</strong>Flask легко установить и настроить.</li>
18 <li><strong>Гибкость</strong>. Микрофреймворк позволяет разработчикам самостоятельно выбирать технологии и инструменты, которые они хотят применять в своих проектах</li>
18 <li><strong>Гибкость</strong>. Микрофреймворк позволяет разработчикам самостоятельно выбирать технологии и инструменты, которые они хотят применять в своих проектах</li>
19 <li><strong>Расширяемость.</strong>Flask позволяет расширять функциональность с помощью плагинов и модулей, которые можно легко интегрировать в проект.</li>
19 <li><strong>Расширяемость.</strong>Flask позволяет расширять функциональность с помощью плагинов и модулей, которые можно легко интегрировать в проект.</li>
20 <li><strong>Активное сообщество</strong>. Flask является одним из самых используемых фреймворков для Python, поэтому имеет большое комьюнити разработчиков.</li>
20 <li><strong>Активное сообщество</strong>. Flask является одним из самых используемых фреймворков для Python, поэтому имеет большое комьюнити разработчиков.</li>
21 </ul><p>При этом у Flask есть и свои недостатки:</p>
21 </ul><p>При этом у Flask есть и свои недостатки:</p>
22 <ul><li><strong>Отсутствие готовых решений.</strong>Разработчики изначально могут использовать во Flask только минимальный набор функциональности. Если же программисту нужны более широкие возможности, такие как аутентификация пользователя, ему придется добавить дополнительные библиотеки или реализовать это самостоятельно.</li>
22 <ul><li><strong>Отсутствие готовых решений.</strong>Разработчики изначально могут использовать во Flask только минимальный набор функциональности. Если же программисту нужны более широкие возможности, такие как аутентификация пользователя, ему придется добавить дополнительные библиотеки или реализовать это самостоятельно.</li>
23 <li><strong>Нет встроенной многопоточности</strong>. Flask был разработан как однопоточный фреймворк. И чтобы управлять многопоточными веб-приложениями, придется установить дополнительные библиотеки.</li>
23 <li><strong>Нет встроенной многопоточности</strong>. Flask был разработан как однопоточный фреймворк. И чтобы управлять многопоточными веб-приложениями, придется установить дополнительные библиотеки.</li>
24 <li><strong>Ограниченные возможности для масштабирования</strong>. Если проект начинает расти и усложняться, то могут появиться сложности в поддержке нужной функциональности.</li>
24 <li><strong>Ограниченные возможности для масштабирования</strong>. Если проект начинает расти и усложняться, то могут появиться сложности в поддержке нужной функциональности.</li>
25 </ul><p>То есть Flask можно удобно использовать в небольших проектах - он идеален для макетирования идей и быстрого прототипирования. При этом его редко используют в крупных проектах, и он плохо подходит для асинхронного программирования.</p>
25 </ul><p>То есть Flask можно удобно использовать в небольших проектах - он идеален для макетирования идей и быстрого прототипирования. При этом его редко используют в крупных проектах, и он плохо подходит для асинхронного программирования.</p>
26 <h2>Как создать проект на Flask</h2>
26 <h2>Как создать проект на Flask</h2>
27 <p>Для начала работы с микрофреймворком нужно<a>скачать</a>последнюю версию Flask:</p>
27 <p>Для начала работы с микрофреймворком нужно<a>скачать</a>последнюю версию Flask:</p>
28 <p>pip install Flask</p>
28 <p>pip install Flask</p>
29 <p>Для примера мы напишем на Flask тестовое веб-приложение с минимальным функционалом. Как работают приложения такого типа:</p>
29 <p>Для примера мы напишем на Flask тестовое веб-приложение с минимальным функционалом. Как работают приложения такого типа:</p>
30 <ul><li>Пользователь вводит в браузере url, например - hexlet.io. В нашем тестовом приложении пользователь не будет вводить url, потому что мы будем работать с локальным сервером по адресу http://127.0.0.1:5000.</li>
30 <ul><li>Пользователь вводит в браузере url, например - hexlet.io. В нашем тестовом приложении пользователь не будет вводить url, потому что мы будем работать с локальным сервером по адресу http://127.0.0.1:5000.</li>
31 <li>Браузер получает у DNS IP-адрес нужного нам сервера. DNS - это Domain Name System, распределенная системе серверов. Она работает как общая "контактная книга" в интернете.</li>
31 <li>Браузер получает у DNS IP-адрес нужного нам сервера. DNS - это Domain Name System, распределенная системе серверов. Она работает как общая "контактная книга" в интернете.</li>
32 <li>Браузер отправляет запрос по этому адресу и получает ответ. Как правило - в виде HTML-страницы.</li>
32 <li>Браузер отправляет запрос по этому адресу и получает ответ. Как правило - в виде HTML-страницы.</li>
33 <li>Браузер отображает содержимое страницы.</li>
33 <li>Браузер отображает содержимое страницы.</li>
34 </ul><p>Итак, создадим файл hello.py и запишем в него следующий код:</p>
34 </ul><p>Итак, создадим файл hello.py и запишем в него следующий код:</p>
35 <p>Давайте подробно разберем, что делает код, который мы написали.</p>
35 <p>Давайте подробно разберем, что делает код, который мы написали.</p>
36 <p>Первой строкой мы импортируем класс Flask. После этого мы создаем объект этого класса, передав первым аргументом имя модуля, - это и будет наше приложение для общения с веб-cервером. __name__ - это удобный способ передать именно то приложение, из которого запущен Flask.</p>
36 <p>Первой строкой мы импортируем класс Flask. После этого мы создаем объект этого класса, передав первым аргументом имя модуля, - это и будет наше приложение для общения с веб-cервером. __name__ - это удобный способ передать именно то приложение, из которого запущен Flask.</p>
37 <p>Декоратор route() сообщает Flask, при обращении к какому URL-адресу запустится декорируемая разработчиком функция - в нашем примере это index. Последней строчкой мы открываем локальный веб-сервер с параметром debug=True - это позволит следить за всеми ошибками в логе программы.</p>
37 <p>Декоратор route() сообщает Flask, при обращении к какому URL-адресу запустится декорируемая разработчиком функция - в нашем примере это index. Последней строчкой мы открываем локальный веб-сервер с параметром debug=True - это позволит следить за всеми ошибками в логе программы.</p>
38 <blockquote><h3>Читайте также:</h3>
38 <blockquote><h3>Читайте также:</h3>
39 <p>Программирование на Python:<a>особенности обучения</a>, перспективы, ситуация на рынке труда</p>
39 <p>Программирование на Python:<a>особенности обучения</a>, перспективы, ситуация на рынке труда</p>
40 </blockquote><p>Запускаем веб-приложение через терминал:</p>
40 </blockquote><p>Запускаем веб-приложение через терминал:</p>
41 <p>python hello.py</p>
41 <p>python hello.py</p>
42 <p>Если мы все сделали правильно, то в терминале появятся эти сообщения:</p>
42 <p>Если мы все сделали правильно, то в терминале появятся эти сообщения:</p>
43 <p>В основном тут отображается служебная информация. Единственное, что нас интересует - сообщение, что наш локальный сервер запущен по адресу http://127.0.0.1:5000/. В нем красными буквами указывается, что локальный сервер не подходит для продакшена. Но, так как мы реализовали тестовое приложение, то не будем деплоить его на реальный сервер.</p>
43 <p>В основном тут отображается служебная информация. Единственное, что нас интересует - сообщение, что наш локальный сервер запущен по адресу http://127.0.0.1:5000/. В нем красными буквами указывается, что локальный сервер не подходит для продакшена. Но, так как мы реализовали тестовое приложение, то не будем деплоить его на реальный сервер.</p>
44 <p>Вернемся к коду. С помощью переменной части маршрута Flask может передавать в функцию аргументы.</p>
44 <p>Вернемся к коду. С помощью переменной части маршрута Flask может передавать в функцию аргументы.</p>
45 <p>В нашем примере значения просто появятся в браузере как часть строки. На стартовой странице нашего сайта будет запускаться функция index(). В ней пользователю, помимо приветствия, будет предлагаться нажать на ссылку, при клике на которую он перейдет на user/Аникин/Георгий. Этот URL-маршрут будет обрабатываться уже функцией get_user.</p>
45 <p>В нашем примере значения просто появятся в браузере как часть строки. На стартовой странице нашего сайта будет запускаться функция index(). В ней пользователю, помимо приветствия, будет предлагаться нажать на ссылку, при клике на которую он перейдет на user/Аникин/Георгий. Этот URL-маршрут будет обрабатываться уже функцией get_user.</p>
46 <p>Функция get_user декорируется @app.route('/&lt;surname&gt;/&lt;name&gt;’), а в адресной строке у нас /user/Аникин/Георгий. То есть наша функция получает аргументы из URL-адреса, эти значения лежат между косых скобок. По умолчанию тип таких значений string принимает любой текст без косой черты. Но переменные маршрутов могут быть и иных типов: int, float, path и других. Типы указываются в формате &lt;тип:имя переменной&gt;.</p>
46 <p>Функция get_user декорируется @app.route('/&lt;surname&gt;/&lt;name&gt;’), а в адресной строке у нас /user/Аникин/Георгий. То есть наша функция получает аргументы из URL-адреса, эти значения лежат между косых скобок. По умолчанию тип таких значений string принимает любой текст без косой черты. Но переменные маршрутов могут быть и иных типов: int, float, path и других. Типы указываются в формате &lt;тип:имя переменной&gt;.</p>
47 <h2>Структура приложения на Flask</h2>
47 <h2>Структура приложения на Flask</h2>
48 <p>Создадим подкаталог flask_app с такой структурой файлов и папок:</p>
48 <p>Создадим подкаталог flask_app с такой структурой файлов и папок:</p>
49 <p>Чтобы написать приложение сложнее одной строки, в директории проекта должны находиться папки static и templates. Директория static содержит ресурсы, которые используются шаблонами. В том числе включая файлы CSS, JavaScript и картинки. Папка templates содержит только шаблоны с расширением *.html.</p>
49 <p>Чтобы написать приложение сложнее одной строки, в директории проекта должны находиться папки static и templates. Директория static содержит ресурсы, которые используются шаблонами. В том числе включая файлы CSS, JavaScript и картинки. Папка templates содержит только шаблоны с расширением *.html.</p>
50 <p>Заполним наши файлы кодом. Сначала - наш основной файл проекта app.py:</p>
50 <p>Заполним наши файлы кодом. Сначала - наш основной файл проекта app.py:</p>
51 <p>После этого - index.html:</p>
51 <p>После этого - index.html:</p>
52 <p>И файл about.html:</p>
52 <p>И файл about.html:</p>
53 <p>Для отображения HTML-шаблонов мы используем функцию render_template(). В нашем коде она принимает только имя шаблона и возвращает строку с результатом рендеринга шаблона.</p>
53 <p>Для отображения HTML-шаблонов мы используем функцию render_template(). В нашем коде она принимает только имя шаблона и возвращает строку с результатом рендеринга шаблона.</p>
54 <p>Однако render_template() может принимать неограниченное количество именованных аргументов, которые можно использовать в этом шаблоне. Это позволит решить проблему нашего тестового проекта - сейчас у нас две функции, две страницы, и очень много дублированного кода.</p>
54 <p>Однако render_template() может принимать неограниченное количество именованных аргументов, которые можно использовать в этом шаблоне. Это позволит решить проблему нашего тестового проекта - сейчас у нас две функции, две страницы, и очень много дублированного кода.</p>
55 <p>Напишем базовый шаблон base.html и пару его наследников. При этом блоки {% block smth %} … {% endblock %} - это части базового шаблона, которые можно заменить в наследнике. Переменные передаются по именам в конструкции {{ variable }}.</p>
55 <p>Напишем базовый шаблон base.html и пару его наследников. При этом блоки {% block smth %} … {% endblock %} - это части базового шаблона, которые можно заменить в наследнике. Переменные передаются по именам в конструкции {{ variable }}.</p>
56 <p>После появления файла с базовым HTML-шаблоном можем поправить наши остальные HTML-файлы:</p>
56 <p>После появления файла с базовым HTML-шаблоном можем поправить наши остальные HTML-файлы:</p>
57 <p>Кроме того, нужно поправить и основной файл Flask-проекта app.py:</p>
57 <p>Кроме того, нужно поправить и основной файл Flask-проекта app.py:</p>
58 <h2>Подключаем Bootstrap</h2>
58 <h2>Подключаем Bootstrap</h2>
59 <p><a>Bootstrap</a>- это открытый и бесплатный набор инструментов для создания сайтов и веб-приложений.</p>
59 <p><a>Bootstrap</a>- это открытый и бесплатный набор инструментов для создания сайтов и веб-приложений.</p>
60 <p>В нашем проекте в папке templates у нас есть подкаталог bootstrap, а в нем файл base.html - это немного модифицированная заготовка сайта-документации Bootstrap-Flask:</p>
60 <p>В нашем проекте в папке templates у нас есть подкаталог bootstrap, а в нем файл base.html - это немного модифицированная заготовка сайта-документации Bootstrap-Flask:</p>
61 <p>В файлах index.html и about.html заменим строку наследования на:</p>
61 <p>В файлах index.html и about.html заменим строку наследования на:</p>
62 <p>Второй путь подключения Bootstrap к проекту на Flask - через CDN. Подробнее об этом можно почитать в документации<a>фреймворка</a>.</p>
62 <p>Второй путь подключения Bootstrap к проекту на Flask - через CDN. Подробнее об этом можно почитать в документации<a>фреймворка</a>.</p>
63 <blockquote><h3>Читайте также:</h3>
63 <blockquote><h3>Читайте также:</h3>
64 <p>Как создатель Python Гвидо ван Россум устроился в Microsoft и теперь работает над<a>развитием CPython</a></p>
64 <p>Как создатель Python Гвидо ван Россум устроился в Microsoft и теперь работает над<a>развитием CPython</a></p>
65 </blockquote><p>После подключения Bootstrap нужно будет немного поправить основной файл нашего проекта app.py:</p>
65 </blockquote><p>После подключения Bootstrap нужно будет немного поправить основной файл нашего проекта app.py:</p>
66 <p>Последним элементом нашего веб-приложения будет форма отправки. Для этого нужно немного модифицировать index.html:</p>
66 <p>Последним элементом нашего веб-приложения будет форма отправки. Для этого нужно немного модифицировать index.html:</p>
67 <p>Вообще, Bootstrap может добавить огромное количество элементов в приложение буквально в несколько кликов. Мы ограничились четырьмя - три поля и одна кнопка. Ключевой элемент здесь - это {{ super() }}.</p>
67 <p>Вообще, Bootstrap может добавить огромное количество элементов в приложение буквально в несколько кликов. Мы ограничились четырьмя - три поля и одна кнопка. Ключевой элемент здесь - это {{ super() }}.</p>
68 <h2>Подключаем базу данных</h2>
68 <h2>Подключаем базу данных</h2>
69 <p>Итак, у нас есть форма отправки, но она пока ничего не делает с данными. Для нас было бы неплохо хранить, обрабатывать и в будущем легко извлекать данные этих форм. Обычно такие задачи решают с помощью реляционных баз данных (далее БД).</p>
69 <p>Итак, у нас есть форма отправки, но она пока ничего не делает с данными. Для нас было бы неплохо хранить, обрабатывать и в будущем легко извлекать данные этих форм. Обычно такие задачи решают с помощью реляционных баз данных (далее БД).</p>
70 <p>Есть большое количество способов работы с SQL-запросами во Flask. Мы можем использовать, например, sqlite3 и чистый SQL, а можем - библиотеку sqlite3 для Python. Кроме того, можно обернуть чистые SQL-запросы в код, либо использовать Psycopg2 для работы с PostgresSQL в Python (мы рекомендуем делать именно так и<a>вот почему</a>). Для примера в этом тексте мы<a>используем</a>библиотеку Flask<a>SQLAlchemy</a>(расширение для Flask), которая предлагает технологию ORM для взаимодействия с БД.</p>
70 <p>Есть большое количество способов работы с SQL-запросами во Flask. Мы можем использовать, например, sqlite3 и чистый SQL, а можем - библиотеку sqlite3 для Python. Кроме того, можно обернуть чистые SQL-запросы в код, либо использовать Psycopg2 для работы с PostgresSQL в Python (мы рекомендуем делать именно так и<a>вот почему</a>). Для примера в этом тексте мы<a>используем</a>библиотеку Flask<a>SQLAlchemy</a>(расширение для Flask), которая предлагает технологию ORM для взаимодействия с БД.</p>
71 <p>Подключаем базу данных к нашему проекту через файл app.py:</p>
71 <p>Подключаем базу данных к нашему проекту через файл app.py:</p>
72 <p>В нашей БД появился класс Event c атрибутами, который наследуется от db.Model. Это позволяет с помощью SQLAlchemy создать таблицу event, а поля нашего класса сделать колонками этой таблицы. Кроме того, мы определили магический метод __str__ для строкового отображения экземпляров класса - это пригодится для отображения в HTML.</p>
72 <p>В нашей БД появился класс Event c атрибутами, который наследуется от db.Model. Это позволяет с помощью SQLAlchemy создать таблицу event, а поля нашего класса сделать колонками этой таблицы. Кроме того, мы определили магический метод __str__ для строкового отображения экземпляров класса - это пригодится для отображения в HTML.</p>
73 <p>Для создания таблицы в блок if __name__ == ‘__main__’ мы добавили команду db.create_all(), а для обработки отправленной формы - метод add_event. Он работает с методом POST, который указывает Flask, что данные будут отправлены на сервер.</p>
73 <p>Для создания таблицы в блок if __name__ == ‘__main__’ мы добавили команду db.create_all(), а для обработки отправленной формы - метод add_event. Он работает с методом POST, который указывает Flask, что данные будут отправлены на сервер.</p>
74 <p>В методе POST мы считываем данные отправленной формы и создаем для каждой строки временную переменную. После этого мы создаем объект event класса Event, передаем наши временные переменные как именованные аргументы, добавляем event в БД и фиксируем изменения.</p>
74 <p>В методе POST мы считываем данные отправленной формы и создаем для каждой строки временную переменную. После этого мы создаем объект event класса Event, передаем наши временные переменные как именованные аргументы, добавляем event в БД и фиксируем изменения.</p>
75 <p>Нам осталось лишь немного поправить форму: в файле index.html в открывающем теге &lt;form&gt; добавим атрибуты action="{{ url_for('add_event') }}" method="POST". Теперь форма отправки по нажатию на кнопку "Записать" будет отправлять данные в базу данных.</p>
75 <p>Нам осталось лишь немного поправить форму: в файле index.html в открывающем теге &lt;form&gt; добавим атрибуты action="{{ url_for('add_event') }}" method="POST". Теперь форма отправки по нажатию на кнопку "Записать" будет отправлять данные в базу данных.</p>
76 <p>Добавим страницу отображения наших записей в новый файл Events.html:</p>
76 <p>Добавим страницу отображения наших записей в новый файл Events.html:</p>
77 <p>В файл app.py добавим view:</p>
77 <p>В файл app.py добавим view:</p>
78 <p>А в основном контейнере index.html добавим ссылку на эту страницу:</p>
78 <p>А в основном контейнере index.html добавим ссылку на эту страницу:</p>
79 <p>Наш тестовый проект на Flask готов! Его можно запустить на локальном сервере через команду python app.py (в некоторых случаях надо будет написать название директории перед названием файла app.py).</p>
79 <p>Наш тестовый проект на Flask готов! Его можно запустить на локальном сервере через команду python app.py (в некоторых случаях надо будет написать название директории перед названием файла app.py).</p>
80 <h2>Что еще почитать про Flask</h2>
80 <h2>Что еще почитать про Flask</h2>
81 <ul><li><a>Большой курс по Flask на Хекслете</a></li>
81 <ul><li><a>Большой курс по Flask на Хекслете</a></li>
82 <li><a>Документация Flask</a></li>
82 <li><a>Документация Flask</a></li>
83 <li><a>Цикл статей на Real Python</a></li>
83 <li><a>Цикл статей на Real Python</a></li>
84 <li><a>Проектирование RESTful API с помощью Python и Flask</a></li>
84 <li><a>Проектирование RESTful API с помощью Python и Flask</a></li>
85 </ul><blockquote><h3>Изучите Python на Хекслете</h3>
85 </ul><blockquote><h3>Изучите Python на Хекслете</h3>
86 <p>Пройдите нашу профессию "<a>Python-разработчик</a>", чтобы поменять свою жизнь и стать бэкенд-программистом.</p>
86 <p>Пройдите нашу профессию "<a>Python-разработчик</a>", чтобы поменять свою жизнь и стать бэкенд-программистом.</p>
87 </blockquote>
87 </blockquote>