<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 19:50:42 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="r_jsJHNlZvh-9Arla924IzP0kGxXSw4b6enCBw3JYx5AKScTgRvLmMi3Ln1n0khU8_29xl988LlUCVhTX86EcA";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Бэкенд на Python | Ключевые аспекты веб-разработки на Python</title>
<meta name="description" content="Бэкенд на Python / Ключевые аспекты веб-разработки на Python: Выясняем, как устроен типичный бэкенд, написанный на Python">
<link rel="canonical" href="https://ru.hexlet.io/courses/python-overview-of-web-development/lessons/web-in-python/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Бэкенд на Python">
<meta property="og:title" content="Ключевые аспекты веб-разработки на Python">
<meta property="og:description" content="Бэкенд на Python / Ключевые аспекты веб-разработки на Python: Выясняем, как устроен типичный бэкенд, написанный на Python">
<meta property="og:url" content="https://ru.hexlet.io/courses/python-overview-of-web-development/lessons/web-in-python/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="SftrO4jqoy_oO5jNqwHz1V6sotg8r6k4TRiwNqpYHremKqAMepQOT154vFWnDgOinqWPcjSYV5rw-Cpi-F_52Q" />
<script src="/vite/assets/inertia-DfXos102.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-cb8xch9l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T19:50:42.082Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"tSbGvSX7K5e3JFNU3LLVkyoGHEOay84cMCbYYMQEF29a9w2K14WG9wFnd8zQvSXk6g8x6ZL8ML6NxkI0lgPwAQ","topics":[{"id":78566,"title":"Поясните пожалуйста смысл предложения:\n\n> Именно Web помогают писать web-фреймворки","plain_title":"Поясните пожалуйста смысл предложения: Именно Web помогают писать web-фреймворки ","creator":{"public_name":"Илья Уваров","id":468528,"is_tutor":false},"comments":[{"creator":{"public_name":"Aleksandr Litvinov","id":117182,"is_tutor":true},"id":162271,"body":"Web-фреймворки помогают писать web-приложения.","topic_id":78566}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":74929,"title":"Подскажите какие материалы из пройденных уроков нужно повторно посмотреть чтобы знать ответ на этот вопрос: \"Допишите команду, чтобы запустить приложение run из модуля web.py\"","plain_title":"Подскажите какие материалы из пройденных уроков нужно повторно посмотреть чтобы знать ответ на этот вопрос: \"Допишите команду, чтобы запустить приложение run из модуля web.py\" ","creator":{"public_name":"Кирилл Досегаев","id":449935,"is_tutor":false},"comments":[{"creator":{"public_name":"Николай Аверин","id":523163,"is_tutor":false},"id":165596,"body":"Было бы несколько более информативно, если бы в примере было указано, что app в данном случае имя скрипта","topic_id":74929},{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":156272,"body":"Добрый день, в уроке есть пример \n\n> сохраните функцию в файл example.py и вызовете команду `gunicorn -w 4 example:app`\n\nто есть вам надо заменить на другое имя модуля и имя функции.","topic_id":74929}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":81357,"title":"Мне одному сложно даются темы и приходится все гуглить, чтоб расшифровать все на понятном языке? Читаешь тут, ничего не понимаешь, приходится каждый урок еще догугливать на час минимум, не понимаю прикола почему не сделать описание подробнее или привести более понятные примеры. поймал себя на мысли что мне легче сначала изучить тему самостоятельно, прежде чем лезть суда что-то читать, так есть шанс что хотя бы что-то пойму. Конечно если у меня у одного так, наверно дело во мне)) Наверно нужно задать какой-то вопрос, а не просто изливать душу :D \nМожет я что-то не так делаю? Материал дается очень тяжело","plain_title":"Мне одному сложно даются темы и приходится все гуглить, чтоб расшифровать все на понятном языке? Читаешь тут, ничего не понимаешь, приходится каждый урок еще догугливать на час минимум, не понимаю прикола почему не сделать описание подробнее или привести более понятные примеры. поймал себя на мысли что мне легче сначала изучить тему самостоятельно, прежде чем лезть суда что-то читать, так есть шанс что хотя бы что-то пойму. Конечно если у меня у одного так, наверно дело во мне)) Наверно нужно задать какой-то вопрос, а не просто изливать душу :D Может я что-то не так делаю? Материал дается очень тяжело ","creator":{"public_name":"Дмитрий Новожилов","id":560758,"is_tutor":false},"comments":[{"creator":{"public_name":"Дмитрий Новожилов","id":560758,"is_tutor":false},"id":166425,"body":"Добрый день! Прогресс по курсу есть, понимания - 0 )) В голове вообще ничего не усваивается. Тесты в основном наугад проходятся. Не понимаю эффективно ли я провожу время. Изучил MVC, но пишу этот коммент и понимаю, что вообще не знаю что это такое, прям боль) Эта каша началась именно в курсе \"Ключевые аспекты веб-разработки на Python\". Слабенький видимо фундамент у меня будет))","topic_id":81357},{"creator":{"public_name":"Artyom Kropp","id":381127,"is_tutor":true},"id":166445,"body":"Это нормально что-то не понимать :) Главное, чтобы у вас в памяти отложились эти понятия. А затем по мере прохождения профессии и постепенного обретения опыта и большего понимания в разработке, эти понятия сложатся в единую картину и все встанет на свои места. Главное не останавливаться и продолжать двигаться вперед. Также не стесняйтесь обращаться к своему наставнику и спрашивать в чатах в slack у других студентов. Зачастую, как раз в таких в таких беседах, находится зерно истины.","topic_id":81357},{"creator":{"public_name":"Artyom Kropp","id":381127,"is_tutor":true},"id":166395,"body":"Добрый день! Данная тема рассматривается как обзорная, которая закладывает фундамент на будущее, дают общую картину современного бекэнда и веб-разработки, чтобы студент практически с самого начала представлял с чем ему предстоит иметь дело. Какие уроки из курса у вас вызвали наибольшее количество проблем?","topic_id":81357}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":86889,"title":"Добрый день! \n\nВ теории говориться: .\"....за веб-сервером обычно находится WSGI-сервер, который запускает WSGI-приложения\"\n\nЭто можно интерпретировать, как за одним сервером есть еще другой сервер. Если это так, то получается, что WSGI это типа прослойка через которую клиент получает доступ к самому серверу на котором находятся данные. Правильно понимаю? Если нет, поясните пжста. ","plain_title":"Добрый день! В теории говориться: .\"....за веб-сервером обычно находится WSGI-сервер, который запускает WSGI-приложения\" Это можно интерпретировать, как за одним сервером есть еще другой сервер. Если это так, то получается, что WSGI это типа прослойка через которую клиент получает доступ к самому серверу на котором находятся данные. Правильно понимаю? Если нет, поясните пжста. ","creator":{"public_name":"Павел Гребеньков","id":428605,"is_tutor":false},"comments":[{"creator":{"public_name":"Artyom Kropp","id":381127,"is_tutor":true},"id":174388,"body":"Добрый день! WSGI-сервер отвечает за запуск WSGI-приложения и обрабатывает запросы которые поступают от клиентов. WSGI-сервер выступает прослойкой между самим WSGI-приложением и клиентом, предоставляя интерфейс для их общения. ","topic_id":86889}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":74924,"title":"Кто-нибудь может объяснить, что автор подразумевал под словом \"коробка\" в варианте ответа \"Нет, не нужно, Python умеет работать с вебом из коробки\"?","plain_title":"Кто-нибудь может объяснить, что автор подразумевал под словом \"коробка\" в варианте ответа \"Нет, не нужно, Python умеет работать с вебом из коробки\"? ","creator":{"public_name":"Кирилл Досегаев","id":449935,"is_tutor":false},"comments":[{"creator":{"public_name":"Кирилл Досегаев","id":449935,"is_tutor":false},"id":156143,"body":"Спасибо за пояснение смыслового обозначения коробки) теперь смысл вопроса понятен","topic_id":74924},{"creator":{"public_name":"Давид","id":431338,"is_tutor":false},"id":156130,"body":"Любой язык программирования обладает своим набором встроенных структур, в том числе библиотеками, расширяющий функционал и возможности языка. Насколько я понимаю, \"из коробки\" значит, что никакие дополнительные структуры подключать не нужно для того, чтобы язык программирования выполнял поставленную задачу. Но в данном случае Python как раз таки нуждается в дополнительных структурах, т.к. он не умеет работать с вебом из коробки. \nЭто как авто, который вам продали в автосалоне на летней резине. Чтобы ездить зимой в гололед, нужно докупить зимние шины, таким образом данный автомобиль не комлектовался зимней резиной \"из коробки\", этот функционал без дополнительных действий отсутствует.","topic_id":74924}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":93486,"title":"Добрый день!\nДля техподдержки - в конце урока ссылка на устаревший Flask (м2.2). \n\nЕсли курс в ближайшее время будут переписывать, как ранее указывали в поддержке, то стоит добавить обновленную версию:\nhttps://flask.palletsprojects.com/en/2.3.x/installation/","plain_title":"Добрый день! Для техподдержки - в конце урока ссылка на устаревший Flask (м2.2). Если курс в ближайшее время будут переписывать, как ранее указывали в поддержке, то стоит добавить обновленную версию: https://flask.palletsprojects.com/en/2.3.x/installation/ ","creator":{"public_name":"Алексей Fedorov","id":697498,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":183524,"body":"Поправил, спасибо","topic_id":93486}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":97838,"title":"При попытке выполнить пример с example.py из урока, получаю ошибку:\n\n[2211] [ERROR] Connection in use: ('127.0.0.1', 8000)\n[2211] [ERROR] Can't connect to ('127.0.0.1', 8000)\n\nЧто я мог сделать неправильно?","plain_title":"При попытке выполнить пример с example.py из урока, получаю ошибку: [2211] [ERROR] Connection in use: ('127.0.0.1', 8000) [2211] [ERROR] Can't connect to ('127.0.0.1', 8000) Что я мог сделать неправильно? ","creator":{"public_name":"Дмитрий Крашенинников","id":759706,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр Корсиков","id":388803,"is_tutor":false},"id":188896,"body":"Предполагаю что у тебя не запущен сервер или запущен но настроен на другой порт (не 8000).\nЕсли работаешь в *VS code* - запусти **Live server** (в правом нижнем углу *VS code* значок излучающей антенны и надпись **Go Live**).","topic_id":97838}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":99976,"title":"Добрый вечер. При выполнении задания по созданию простого рабочего веб-приложения \n(... вызываем команду gunicorn -w 4 example:app) выполнил следующие команды в своем терминале:\n\n1. pip install gunicorn #как того требует инструкция на gunicorn.org\n2. touch example.py #в корневом каталоге\nвставляю в \"example.py\" код из примера (def app(environ, start_response): ...)\n3. gunicorn -w 4 example:app\nПОЛУЧАЮ ВОТ ТАКОЙ ОТВЕТ:\n[2024-05-04 19:52:03 +0300] [11322] [INFO] Starting gunicorn 22.0.0\n[2024-05-04 19:52:03 +0300] [11322] [INFO] Listening at: http://127.0.0.1:8000 (11322)\n[2024-05-04 19:52:03 +0300] [11322] [INFO] Using worker: sync\n[2024-05-04 19:52:03 +0300] [11323] [INFO] Booting worker with pid: 11323\n[2024-05-04 19:52:04 +0300] [11324] [INFO] Booting worker with pid: 11324\n[2024-05-04 19:52:04 +0300] [11325] [INFO] Booting worker with pid: 11325\n[2024-05-04 19:52:04 +0300] [11326] [INFO] Booting worker with pid: 11326\n^C[2024-05-04 20:13:05 +0300] [11322] [INFO] Handling signal: int\n[2024-05-04 20:13:06 +0300] [11325] [INFO] Worker exiting (pid: 11325)\n[2024-05-04 20:13:06 +0300] [11326] [INFO] Worker exiting (pid: 11326)\n[2024-05-04 20:13:06 +0300] [11324] [INFO] Worker exiting (pid: 11324)\n[2024-05-04 20:13:06 +0300] [11323] [INFO] Worker exiting (pid: 11323)\n[2024-05-04 20:13:06 +0300] [11322] [INFO] Shutting down: Master\n\nВопрос: что я делаю не так?","plain_title":"Добрый вечер. При выполнении задания по созданию простого рабочего веб-приложения (... вызываем команду gunicorn -w 4 example:app) выполнил следующие команды в своем терминале: pip install gunicorn #как того требует инструкция на gunicorn.org touch example.py #в корневом каталоге вставляю в \"example.py\" код из примера (def app(environ, start_response): ...) gunicorn -w 4 example:app ПОЛУЧАЮ ВОТ ТАКОЙ ОТВЕТ: [2024-05-04 19:52:03 +0300] [11322] [INFO] Starting gunicorn 22.0.0 [2024-05-04 19:52:03 +0300] [11322] [INFO] Listening at: http://127.0.0.1:8000 (11322) [2024-05-04 19:52:03 +0300] [11322] [INFO] Using worker: sync [2024-05-04 19:52:03 +0300] [11323] [INFO] Booting worker with pid: 11323 [2024-05-04 19:52:04 +0300] [11324] [INFO] Booting worker with pid: 11324 [2024-05-04 19:52:04 +0300] [11325] [INFO] Booting worker with pid: 11325 [2024-05-04 19:52:04 +0300] [11326] [INFO] Booting worker with pid: 11326 ^C[2024-05-04 20:13:05 +0300] [11322] [INFO] Handling signal: int [2024-05-04 20:13:06 +0300] [11325] [INFO] Worker exiting (pid: 11325) [2024-05-04 20:13:06 +0300] [11326] [INFO] Worker exiting (pid: 11326) [2024-05-04 20:13:06 +0300] [11324] [INFO] Worker exiting (pid: 11324) [2024-05-04 20:13:06 +0300] [11323] [INFO] Worker exiting (pid: 11323) [2024-05-04 20:13:06 +0300] [11322] [INFO] Shutting down: Master Вопрос: что я делаю не так? ","creator":{"public_name":"Андрей Жданов","id":553581,"is_tutor":false},"comments":[{"creator":{"public_name":"Андрей Жданов","id":553581,"is_tutor":false},"id":191507,"body":"И что было по плану?)","topic_id":99976},{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":191624,"body":"А зачем вы его остановили через ctrl-C? У вас запустится сервер, дальше вы можете перейти по ссылке, которую он вам указывает в логе http://127.0.0.1:8000 и увидеть ответ сервера. И остановить его принудительно вы можете командой ctrl-C в теминале где он запущен","topic_id":99976}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":100581,"title":"выполняем задание из теории\n`xantol@DESKTOP-LFS6BCE:~$ gunicorn -w 4 example:app\n[2024-05-28 11:58:27 +0500] [4995] [INFO] Starting gunicorn 22.0.0\n[2024-05-28 11:58:27 +0500] [4995] [INFO] Listening at: http://127.0.0.1:8000 (4995)\n[2024-05-28 11:58:27 +0500] [4995] [INFO] Using worker: sync\n[2024-05-28 11:58:27 +0500] [4997] [INFO] Booting worker with pid: 4997\n[2024-05-28 11:58:27 +0500] [4998] [INFO] Booting worker with pid: 4998\n[2024-05-28 11:58:27 +0500] [4999] [INFO] Booting worker with pid: 4999\n[2024-05-28 11:58:27 +0500] [5000] [INFO] Booting worker with pid: 5000`\nЧто дальше?\n Почему не объясняется ничего. В теме даны некоторые определение, все остальное просто для увеличения объема? И бесполезный тест который приведен дальше.","plain_title":"выполняем задание из теории xantol@DESKTOP-LFS6BCE:~$ gunicorn -w 4 example:app [2024-05-28 11:58:27 +0500] [4995] [INFO] Starting gunicorn 22.0.0 [2024-05-28 11:58:27 +0500] [4995] [INFO] Listening at: http://127.0.0.1:8000 (4995) [2024-05-28 11:58:27 +0500] [4995] [INFO] Using worker: sync [2024-05-28 11:58:27 +0500] [4997] [INFO] Booting worker with pid: 4997 [2024-05-28 11:58:27 +0500] [4998] [INFO] Booting worker with pid: 4998 [2024-05-28 11:58:27 +0500] [4999] [INFO] Booting worker with pid: 4999 [2024-05-28 11:58:27 +0500] [5000] [INFO] Booting worker with pid: 5000 Что дальше? Почему не объясняется ничего. В теме даны некоторые определение, все остальное просто для увеличения объема? И бесполезный тест который приведен дальше. ","creator":{"public_name":"Станислав Золотухин","id":822200,"is_tutor":false},"comments":[{"creator":{"public_name":"Станислав Золотухин","id":822200,"is_tutor":false},"id":192316,"body":"> Вам нужно зайти по ссылке, которую вам предоставит гуникорн в выводе. Например выше ваша ссылка \n\n\n\nБыло бы здорово, если так и написали бы в курсе ;)","topic_id":100581},{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":192306,"body":"Вам нужно зайти по ссылке, которую вам предоставит гуникорн в выводе. Например выше ваша ссылка `http://127.0.0.1:8000`\n\nНо вцелом пока весь этот курс и этот урок это подготовка/затравка к будущим темам. Конкретно веб-разработка будет несколькими модулями позже.","topic_id":100581}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}},{"id":105975,"title":"Застрял на тесте . Помогите пожалуйста . Почему не web:app ???","plain_title":"Застрял на тесте . Помогите пожалуйста . Почему не web:app ??? ","creator":{"public_name":"Вячеслав Стадник","id":708166,"is_tutor":false},"comments":[{"creator":{"public_name":"Ivan Mamtsev","id":294764,"is_tutor":true},"id":198765,"body":"Потому что модуля `app` нет в вопросе","topic_id":105975}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Бэкенд на Python","entity_url":null,"active":true}}],"lesson":{"exercise":null,"units":[{"id":3334,"name":"theory","url":"/courses/python-overview-of-web-development/lessons/web-in-python/theory_unit"},{"id":6485,"name":"quiz","url":"/courses/python-overview-of-web-development/lessons/web-in-python/quiz_unit"}],"links":[{"id":423814,"name":"Django","url":"https://www.djangoproject.com/"},{"id":423815,"name":"Flask","url":"https://flask.palletsprojects.com/"}],"ordered_units":[{"id":3334,"name":"theory","url":"/courses/python-overview-of-web-development/lessons/web-in-python/theory_unit"},{"id":6485,"name":"quiz","url":"/courses/python-overview-of-web-development/lessons/web-in-python/quiz_unit"}],"id":1571,"slug":"web-in-python","state":"approved","name":"Бэкенд на Python","course_order":110,"goal":"Выясняем, как устроен типичный бэкенд, написанный на Python","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"В этом уроке вы узнаете, из каких компонентов состоит бэкенд на Python — мы познакомимся с ключевыми терминами курса.\n\n## Веб-сервер\n\nБольшинство веб-приложений построено на клиент-серверной модели:\n\n* **Клиент**: Пользователь открывает браузер и отправляет запрос\n* **Сервер**: Запрос от браузера поступает на **веб-сервер**, который начинает обрабатывать его\n\nНекоторые языки встраивают веб-сервер прямо в свое приложение, но большинство интерпретируемых языков использует специальную внешнюю программу.\n\nТаких самостоятельных веб-серверов существует несколько, но наиболее популярен **Nginx**. Он обрабатывает входящие запросы, отдает статические файлы и распределяет запросы между веб-приложениями.\n\n## WSGI\n\nЕсли бэкенд веб-приложения написан на Python, за веб-сервером обычно находится **WSGI-сервер**, который запускает **WSGI-приложения**. Рассмотрим подробнее, что это такое.\n\n**WSGI** (Web Server Gateway Interface) — это такая абстракция, согласно которой происходит ответ на запросы. По сути это Python-функция, принимающая запрос и возвращающая ответ.\n\nСамое простое WSGI-приложение выглядит примерно так:\n\n```python\n# Код ниже может казаться непонятным, но это не так важно\n# Главное — мы видим, что это всего лишь одна функция\n\ndef app(environ, start_response):\n data = b\"Hello, World!\\n\"\n start_response(\"200 OK\", [\n (\"Content-Type\", \"text/plain\"),\n (\"Content-Length\", str(len(data)))\n ])\n return iter([data])\n```\n\nРассмотрим этот фрагмент кода подробнее:\n\n* Сначала все, что касается конкретного запроса, приходит в аргументе `environ`\n* Затем функция `start_response` устанавливает параметры ответа — здесь это размер ответа и тип содержимого\n* Далее функция просто возвращает итератор, построчно отдающий ответ\n\nСамое простое рабочее веб-приложение можно получить довольно просто:\n\n* Берем популярный WSGI-сервер [gunicorn](https://gunicorn.org/)\n* Сохраняем функцию в файл `example.py`\n* Вызываем команду `gunicorn -w 4 example:app`\n* Переходим по ссылке в выводе gunicorn и видим ответ сервера\n\n## Веб-фреймворк\n\nВыше мы увидели довольно простое веб-приложение. Пусть оно и работает, но на любой запрос оно будет возвращать один и тот же текст. Что-то более сложное написать в таком стиле будет проблематично, пусть и выполнимо.\n\nЧтобы упростить жизнь бэкенд-разработчика и помочь ему реализовывать типичные приложения, используются **фреймворки** — библиотеки, задающие готовую структуру приложения.\n\nВ эту структуру разработчику нужно только вписывать свои фрагменты кода, при этом сам скелет приложения уже готов к применению. Самые популярные веб-фреймворки для Python — это **Django** и **Flask**.\n\nВеб-фреймворки берут на себя много разных задач:\n\n* Выполняют маршрутизацию\n* Упрощают работу с заголовками и данными запросов\n* Формируют ответы в разных форматах\n* Сохраняют истории запросов в файлы для статистики и отладки\n\n## ORM и шаблонизатор\n\nЧто же еще находится в бэкенде, кроме обработки запросов? Чаще всего там есть **ORM** и **шаблонизатор**.\n\n**ORM** (Object-Relational Mapping) — это средство работы с записями в базах данных, предоставляющие записи в виде понятных для языка программирования объектов.\n\n**Шаблонизатор** — это средство, позволяющее писать HTML и CSS в отдельных файлах, а затем модифицировать их содержимое из кода так, чтобы верстка отображала нужные данные. Шаблонизатор дает возможность сверстать макет один раз, а потом программно получать из макета разные страницы.\n\nDjango и некоторые другие веб-фреймворки уже включают в себя ORM и шаблонизатор. \n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":3335,"name":"theory","url":"/courses/python-overview-of-web-development/lessons/intro/theory_unit"}],"links":[],"ordered_units":[{"id":3335,"name":"theory","url":"/courses/python-overview-of-web-development/lessons/intro/theory_unit"}],"id":1572,"slug":"intro","state":"approved","name":"Введение","course_order":100,"goal":"Знакомимся с темой курса","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Вы уже умеете пользоваться языком в целом. Этот навык ценен сам по себе и необходим каждому программисту на Python.\n\nPython — язык общего назначения, а значит может применяться в самых разных областях. С его помощью можно выполнять довольно специфичные задачи — например, писать скрипты для автоматизации. Но такими простыми задачами Python не ограничивается, ведь есть и более глобальные сферы его применения — например, Data Science. И чем больше предметная область, тем больше нужно знать программисту.\n\nОдна из больших областей применения Python — это веб-разработка. Большая часть веб-приложений построена по клиент-серверной модели. Если коротко, то клиент делает запрос на сервер, сервер готовит ответ и отправляет его обратно клиенту. Такие веб-приложения условно делятся на две части:\n\n* Фронтенд — часть веб-приложения, которая работает **на клиенте**, то есть в браузере пользователя\n* Бэкенд — часть, которая работает **на сервере** (ее можно написать на Python)\n\nПодробнее об этой модели мы поговорим далее в курсе. Еще мы рассмотрим все остальные темы, которые важны при разработке веб-приложений Python:\n\n* Получение запросов от клиента\n* Хранение и обработку баз данных\n* Формирование HTML-страниц или других представлений из баз данных\n* Выдачу результата по разным каналам — отображение в браузере, отправка почты, Flash-уведомления и тому подобное\n"},"id":196,"slug":"python-overview-of-web-development","challenges_count":0,"name":"Ключевые аспекты веб-разработки на Python","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы изучите основные аспекты современной веб-разработки в Python. Вы узнаете о сетевых протоколах и интерфейсах, базах данных и ORM, веб-фреймворках и концепции MVC. Знания из этого курса помогут определиться с дальнейшими областями изучения, дадут общую картину современного бекэнда и веб-разработки.","kind":"additional","updated_at":"2026-01-20T11:44:20.017Z","language":"python","duration_cache":13800,"skills":["Познакомиться с MVC и ORM","Создавать простейшие страницы с использованием Python","Устанавливать и запускать приложение на микрофреймворке Flask","Реалистично оценивать объем знаний, необходимых для профессиональной разработки"],"keywords":["HTTP","фреймворки","ORM","тестирование","коллекции","шаблонизация"],"lessons_count":13,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NzA3MSwicHVyIjoiYmxvYl9pZCJ9fQ==--0ddf5bc72ca6c772eb3560ac661c8c302185b63c/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/image.png"},"recommendedLandings":[],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/python-overview-of-web-development/lessons/web-in-python/theory_unit","version":"8f286f6358a90a7bef2263b3a6edf5a90a94fa42","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Ключевые аспекты веб-разработки на Python</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Бэкенд на Python</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Бэкенд на Python","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"Ключевые аспекты веб-разработки на Python"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>В этом уроке вы узнаете, из каких компонентов состоит бэкенд на Python — мы познакомимся с ключевыми терминами курса.</p>
<h2 id="heading-2-1">Веб-сервер</h2>
<p>Большинство веб-приложений построено на клиент-серверной модели:</p>
<ul>
<li><strong>Клиент</strong>: Пользователь открывает браузер и отправляет запрос</li>
<li><strong>Сервер</strong>: Запрос от браузера поступает на <strong>веб-сервер</strong>, который начинает обрабатывать его</li>
</ul>
<p>Некоторые языки встраивают веб-сервер прямо в свое приложение, но большинство интерпретируемых языков использует специальную внешнюю программу.</p>
<p>Таких самостоятельных веб-серверов существует несколько, но наиболее популярен <strong>Nginx</strong>. Он обрабатывает входящие запросы, отдает статические файлы и распределяет запросы между веб-приложениями.</p>
<h2 id="heading-2-2">WSGI</h2>
<p>Если бэкенд веб-приложения написан на Python, за веб-сервером обычно находится <strong>WSGI-сервер</strong>, который запускает <strong>WSGI-приложения</strong>. Рассмотрим подробнее, что это такое.</p>
<p><strong>WSGI</strong> (Web Server Gateway Interface) — это такая абстракция, согласно которой происходит ответ на запросы. По сути это Python-функция, принимающая запрос и возвращающая ответ.</p>
<p>Самое простое WSGI-приложение выглядит примерно так:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"># Код ниже может казаться непонятным, но это не так важно
# Главное — мы видим, что это всего лишь одна функция
def app(environ, start_response):
data = b"Hello, World!\n"
start_response("200 OK", [
("Content-Type", "text/plain"),
("Content-Length", str(len(data)))
])
return iter([data])</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Рассмотрим этот фрагмент кода подробнее:</p>
<ul>
<li>Сначала все, что касается конкретного запроса, приходит в аргументе <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">environ</code></li>
<li>Затем функция <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">start_response</code> устанавливает параметры ответа — здесь это размер ответа и тип содержимого</li>
<li>Далее функция просто возвращает итератор, построчно отдающий ответ</li>
</ul>
<p>Самое простое рабочее веб-приложение можно получить довольно просто:</p>
<ul>
<li>Берем популярный WSGI-сервер <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://gunicorn.org/" rel="noopener noreferrer" target="_blank">gunicorn</a></li>
<li>Сохраняем функцию в файл <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">example.py</code></li>
<li>Вызываем команду <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">gunicorn -w 4 example:app</code></li>
<li>Переходим по ссылке в выводе gunicorn и видим ответ сервера</li>
</ul>
<h2 id="heading-2-3">Веб-фреймворк</h2>
<p>Выше мы увидели довольно простое веб-приложение. Пусть оно и работает, но на любой запрос оно будет возвращать один и тот же текст. Что-то более сложное написать в таком стиле будет проблематично, пусть и выполнимо.</p>
<p>Чтобы упростить жизнь бэкенд-разработчика и помочь ему реализовывать типичные приложения, используются <strong>фреймворки</strong> — библиотеки, задающие готовую структуру приложения.</p>
<p>В эту структуру разработчику нужно только вписывать свои фрагменты кода, при этом сам скелет приложения уже готов к применению. Самые популярные веб-фреймворки для Python — это <strong>Django</strong> и <strong>Flask</strong>.</p>
<p>Веб-фреймворки берут на себя много разных задач:</p>
<ul>
<li>Выполняют маршрутизацию</li>
<li>Упрощают работу с заголовками и данными запросов</li>
<li>Формируют ответы в разных форматах</li>
<li>Сохраняют истории запросов в файлы для статистики и отладки</li>
</ul>
<h2 id="heading-2-4">ORM и шаблонизатор</h2>
<p>Что же еще находится в бэкенде, кроме обработки запросов? Чаще всего там есть <strong>ORM</strong> и <strong>шаблонизатор</strong>.</p>
<p><strong>ORM</strong> (Object-Relational Mapping) — это средство работы с записями в базах данных, предоставляющие записи в виде понятных для языка программирования объектов.</p>
<p><strong>Шаблонизатор</strong> — это средство, позволяющее писать HTML и CSS в отдельных файлах, а затем модифицировать их содержимое из кода так, чтобы верстка отображала нужные данные. Шаблонизатор дает возможность сверстать макет один раз, а потом программно получать из макета разные страницы.</p>
<p>Django и некоторые другие веб-фреймворки уже включают в себя ORM и шаблонизатор.</p></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/python-overview-of-web-development/lessons/web-in-python/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 13</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/python-overview-of-web-development/lessons/web-in-python/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-Bukl1lYy.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>