{"id":444897,"date":"2025-01-13T15:16:21","date_gmt":"2025-01-13T15:16:21","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=444897"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=444897","title":{"rendered":"<span>FastAPI \u0438 Vue.js 3: \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442 \u0441 MiniApp \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439. \u041f\u0438\u0448\u0435\u043c \u0431\u044d\u043a\u0435\u043d\u0434<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0440\u0430\u0434 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0430\u043c \u043d\u043e\u0432\u044b\u0439 \u043a\u0440\u0443\u043f\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u043d\u0435\u0435 \u043d\u0435 \u043e\u0441\u0432\u0435\u0449\u0430\u043b\u0438\u0441\u044c \u0432 \u043c\u043e\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430 \u0441 MiniApp (\u0440\u0430\u043d\u0435\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u043c \u043a\u0430\u043a WebApp) \u2014 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0431\u043e\u0442 \u0441 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043c\u0438\u043d\u0438-\u0441\u0430\u0439\u0442\u043e\u043c \u043f\u0440\u044f\u043c\u043e \u0432 Telegram. \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u0432\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430:<\/p>\n<ul>\n<li>\n<p>FastAPI \u2014 \u043c\u043e\u0449\u043d\u044b\u0439 Python-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u043c \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 API \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0431\u044d\u043a\u0435\u043d\u0434 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0438\u0439, \u043a\u0430\u043a API \u043c\u0435\u0442\u043e\u0434\u044b, \u0442\u0430\u043a \u0438 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c \u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>Vue.js 3 \u2014 JavaScript-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0437\u0430 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u0438\u0445 \u0434\u0432\u0443\u0445 \u0441\u0442\u043e\u043b\u043f\u043e\u0432, \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438\u0437 \u043c\u0438\u0440\u0430 Python \u0438 JavaScript, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043c \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u0441 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041e \u043d\u0438\u0445 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0441\u0442\u0435\u043a \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439.<\/p>\n<h3>\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c?<\/h3>\n<p>\u041d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u2014 \u044d\u0442\u043e \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442 \u0434\u043b\u044f \u0432\u044b\u0434\u0443\u043c\u0430\u043d\u043d\u043e\u0439 \u043a\u043b\u0438\u043d\u0438\u043a\u0438 \u00ab\u0417\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u041f\u043b\u044e\u0441\u00bb. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043a \u0432\u0440\u0430\u0447\u0443 \u0432 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0434\u0435\u043d\u044c \u0438 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p>\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u2014 \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0443. \u042f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u044d\u0442\u043e\u0442 \u0431\u043b\u043e\u043a \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0442\u043e\u0433\u0434\u0430 \u043a\u0430\u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u0442\u0440\u0435\u0445 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>API \u2014 \u0441\u0435\u0440\u0434\u0446\u0435\u0432\u0438\u043d\u0430 \u043b\u043e\u0433\u0438\u043a\u0438, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u0444\u0430\u0439\u043b\u044b \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442 \u2014 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u0435\u0437 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API \u043d\u0430 \u0431\u0430\u0437\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 HTTPX, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0439 \u0441 FastApi.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u2014 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b:<\/p>\n<ul>\n<li>\n<p>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0432\u044b\u0431\u043e\u0440\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f (\u0442\u0435\u0440\u0430\u043f\u0438\u044f, \u0441\u0442\u043e\u043c\u0430\u0442\u043e\u043b\u043e\u0433\u0438\u044f \u0438 \u0442. \u0434.) \u0441 \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u043e\u0438\u0441\u043a\u043e\u043c. \u041e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0432\u0438\u0434\u0435 \u043a\u0430\u0440\u0442\u043e\u0447\u0435\u043a, \u043a\u0430\u043a \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0440\u0430\u0447\u0430 \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430 \u043f\u0440\u0438\u0435\u043c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u043b\u043e\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b \u00ab\u041e \u043d\u0430\u0441\u00bb.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0438 \u0447\u0435\u0440\u0435\u0437 MiniApp.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432\u0441\u0435\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 \u043d\u0430\u043f\u0438\u0448\u0435\u043c API, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0447\u0438\u0441\u0442\u044b\u0439 Telegram Bot API \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 HTTPX.<\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/67849fd95d5079d77e30a356\" data-style=\"\" id=\"67849fd95d5079d77e30a356\" width=\"\"><\/div>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0431\u044d\u043a\u0435\u043d\u0434\u0430: API-\u043c\u0435\u0442\u043e\u0434\u044b, Telegram \u0431\u043e\u0442 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 (\u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e). \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0447\u0430\u0441\u0442\u0438 \u043d\u0430 VUE.JS 3.<\/p>\n<h3>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0442\u0435\u043a<\/h3>\n<p><strong>\u0421\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430<\/strong>:<\/p>\n<ul>\n<li>\n<p>Tailwind CSS \u2014 \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0438\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0431\u0435\u0437 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f CSS \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<\/li>\n<li>\n<p>FontAwesome \u2014 \u0434\u043b\u044f \u0438\u043a\u043e\u043d\u043e\u043a.<\/p>\n<\/li>\n<\/ul>\n<p><strong>Python<\/strong>:<\/p>\n<ul>\n<li>\n<p>FastAPI \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 API.<\/p>\n<\/li>\n<li>\n<p>SQLAlchemy 2 \u2014 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f SQLite).<\/p>\n<\/li>\n<li>\n<p>Apscheduler \u2014 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439).<\/p>\n<\/li>\n<li>\n<p>HTTPX \u2014 \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 Telegram API.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e: Loguru, Pydantic 2, Uvicorn \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<p><strong>JavaScript<\/strong>:<\/p>\n<ul>\n<li>\n<p>Vue.js 3 \u2014 \u043e\u0441\u043d\u043e\u0432\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430.<\/p>\n<\/li>\n<li>\n<p>VueRouter \u2014 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>useFetch \u2014 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API.<\/p>\n<\/li>\n<li>\n<p>VueTG \u2014 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e MiniApp.<\/p>\n<\/li>\n<\/ul>\n<h3>\u042d\u0442\u0430\u043f\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h3>\n<ol>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 SQLAlchemy, Aiosqlite \u0438 Alembic.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 API \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c HTTPX.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 (APSCHEDULER).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u043d\u0430 Vue.js 3.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0435\u043f\u043b\u043e\u0439.<\/p>\n<\/li>\n<\/ol>\n<h3>\u0414\u0435\u043f\u043b\u043e\u0439<\/h3>\n<p>\u0425\u043e\u0447\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0434\u0435\u043f\u043b\u043e\u044f. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u044e \u0432\u0430\u043c \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u0435\u043f\u043b\u043e\u0439 \u0434\u0432\u0430\u0436\u0434\u044b: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u044d\u043a\u0435\u043d\u0434-\u0447\u0430\u0441\u0442\u044c, \u0430 \u0437\u0430\u0442\u0435\u043c \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434.<\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441 <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\">Amvera Cloud<\/a>. \u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u044f \u0432\u044b\u0431\u0438\u0440\u0430\u044e \u0437\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0443 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c. \u0422\u043e \u0435\u0441\u0442\u044c, \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u043a\u043e\u0434\u0438\u043d\u0433\u0435, \u0442\u043e \u0432\u044b \u0442\u043e\u0447\u043d\u043e \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f. \u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438, \u0434\u0435\u043f\u043b\u043e\u0439 \u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u0434\u043d\u0430 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0448\u0430\u0433\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430 \u0441 HTTPS.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0431\u043e\u0440\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a \u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u0430\u043a \u043e\u043f\u0438\u0441\u0430\u043b \u0432\u044b\u0448\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0441\u0442\u0430\u0442\u044c\u044e \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0430\u043c \u044d\u0442\u043e\u0442 \u0431\u043b\u043e\u043a \u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e.<\/p>\n<h4>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440<\/h4>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u043c\u0441\u044f \u0432 \u043a\u043e\u0434, \u0445\u043e\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043b \u0443\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u0435\u0441\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0432 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u0435\u0433\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043d\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u044b \u0447\u0438\u0442\u0430\u0435\u0442\u0435 <strong>\u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u044c<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0431\u044d\u043a\u0435\u043d\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e:<\/p>\n<ul>\n<li>\n<p><strong>API-\u043c\u0435\u0442\u043e\u0434\u044b<\/strong>,<\/p>\n<\/li>\n<li>\n<p><strong>Telegram-\u0431\u043e\u0442<\/strong>,<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u043e\u0433\u0438\u043a\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/strong>.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u043d\u0430 Vue.JS 3, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u044d\u0442\u0438\u043c API.<\/p>\n<p>\u042f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c \u0432\u0441\u0451 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u0432\u0430\u0441 \u0441\u043c\u043e\u0433 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f. \u041d\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u0432 \u043c\u043d\u043e\u0433\u043e\u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043c\u0430\u0440\u0430\u0444\u043e\u043d, \u044f \u0431\u0443\u0434\u0443 \u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u0438\u0437\u043b\u0438\u0448\u043d\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439. \u0415\u0441\u043b\u0438 \u0432\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0438\u0437 \u044d\u0442\u0438\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043c\u043e\u0438\u043c\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c\u0438 \u0441\u0442\u0430\u0442\u044c\u044f\u043c\u0438, \u0433\u0434\u0435 \u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b <strong>FastAPI<\/strong> \u0438 <strong>SQLAlchemy<\/strong>. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b.<\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f <strong>Vue.js 3<\/strong>, \u0440\u0430\u043d\u0435\u0435 \u044f \u043e \u043d\u0451\u043c \u043d\u0435 \u043f\u0438\u0441\u0430\u043b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u044b \u044d\u0442\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u0430\u043c \u043b\u0435\u0433\u0447\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u043d\u0443\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0433\u043b\u044f\u043d\u0438\u0442\u0435 \u0432 \u043c\u043e\u0451 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e <strong>\u00ab<\/strong><a href=\"https:\/\/t.me\/PythonPathMaster\"><strong>\u041b\u0451\u0433\u043a\u0438\u0439 \u043f\u0443\u0442\u044c \u0432 Python<\/strong><\/a><strong>\u00bb<\/strong>. \u041d\u0430\u0441 \u0443\u0436\u0435 \u0431\u043e\u043b\u0435\u0435 2000 \u0435\u0434\u0438\u043d\u043e\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430. \u0422\u0430\u043c \u0432\u044b \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u044d\u043a\u0441\u043a\u043b\u044e\u0437\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u0432\u043e\u0451\u043c Telegram-\u043a\u0430\u043d\u0430\u043b\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0434\u0430\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043c\u043d\u0435 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430.<\/p>\n<p>\u041a\u0441\u0442\u0430\u0442\u0438, \u043f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u0443\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0442\u0435 \u0435\u0451 \u043b\u0430\u0439\u043a\u043e\u043c \u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c. \u0414\u043b\u044f \u043c\u0435\u043d\u044f \u044d\u0442\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0442\u0438\u0432\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c, \u043d\u043e \u0438 \u043b\u0443\u0447\u0448\u0438\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u044f \u043d\u0430 \u0432\u0435\u0440\u043d\u043e\u043c \u043f\u0443\u0442\u0438.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c!<\/p>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0431\u044d\u043a\u0435\u043d\u0434\u0430<\/h3>\n<p><strong>\u0428\u0430\u0433 1: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/strong><\/p>\n<p>\u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u2014 \u044d\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043b\u044e\u0431\u0438\u043c\u043e\u0435 IDE, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u044b \u043f\u0440\u0438\u0432\u044b\u043a\u043b\u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 Python, \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442. \u042f, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u0432\u044b\u0431\u0438\u0440\u0430\u044e PyCharm.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u044f\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b <code>requirements.txt<\/code>. \u0417\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"css\">fastapi==0.115.0 pydantic==2.9.2 uvicorn==0.31.0 pydantic_settings==2.7.1 loguru==0.7.2 SQLAlchemy==2.0.35 aiosqlite==0.20.0 alembic==1.14.0 httpx==0.28.1 apscheduler==3.11.0 pytz==2024.2<\/code><\/pre>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:<\/p>\n<pre><code class=\"bash\">pip install -r requirements.txt<\/code><\/pre>\n<p><strong>\u0428\u0430\u0433 2: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/strong><\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0430\u0436\u043d\u044b\u0439 \u044d\u0442\u0430\u043f \u2014 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 .env. \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0435\u0433\u043e \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438:<\/p>\n<pre><code class=\"css\">ADMIN_IDS=[12345] BASE_SITE=http:\/\/127.0.0.1:8000 BOT_TOKEN=your_bot_token TG_API_SITE=https:\/\/api.telegram.org FRONT_SITE=http:\/\/127.0.0.1:3000<\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u0430\u0436\u0434\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e:<\/p>\n<ul>\n<li>\n<p><code>ADMIN_IDS<\/code> \u2014 \u0441\u043f\u0438\u0441\u043e\u043a Telegram ID \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0432\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0435\u0433\u043e ID \u0438 ID \u043b\u044e\u0431\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0438\u043c \u0431\u043e\u0442\u043e\u043c: <a href=\"https:\/\/t.me\/get_tg_ids_universeBOT\">Telegram-\u0431\u043e\u0442\u043e\u043c<\/a>.<\/p>\n<\/li>\n<li>\n<p><code>BASE_SITE<\/code> \u2014 \u0430\u0434\u0440\u0435\u0441, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u0430\u0448 FastAPI. \u0423\u043a\u0430\u0437\u0430\u043d \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430. \u041f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435 \u0437\u0430\u043c\u0435\u043d\u0438\u043c \u0435\u0433\u043e \u043d\u0430 \u0442\u043e\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\">Amvera Cloud<\/a> (\u0430\u0434\u0440\u0435\u0441 \u0431\u0435\u0437 \u0441\u043b\u0435\u0448\u0430 \u0432 \u043a\u043e\u043d\u0446\u0435).<\/p>\n<\/li>\n<li>\n<p><code>BOT_TOKEN<\/code> \u2014 \u0442\u043e\u043a\u0435\u043d \u0432\u0430\u0448\u0435\u0433\u043e Telegram-\u0431\u043e\u0442\u0430. \u0415\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/t.me\/BotFather\">BotFather<\/a>.<\/p>\n<\/li>\n<li>\n<p><code>TG_API_SITE<\/code> \u2014 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 API Telegram.<\/p>\n<\/li>\n<li>\n<p><code>FRONT_SITE<\/code> \u2014 \u0430\u0434\u0440\u0435\u0441 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0434\u043e \u043d\u0435\u0433\u043e \u043c\u044b \u0434\u043e\u0431\u0435\u0440\u0451\u043c\u0441\u044f \u043f\u043e\u0437\u0436\u0435).<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0428\u0430\u0433 3: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/strong><\/p>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0434\u0432\u0435 \u043f\u0430\u043f\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><code>data<\/code> \u2014 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 SQLite.<\/p>\n<\/li>\n<li>\n<p><code>app<\/code> \u2014 \u0434\u043b\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 FastApi \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0430\u043f\u043a\u0438 app:<\/p>\n<ul>\n<li>\n<p><code>api<\/code> \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b API.<\/p>\n<\/li>\n<li>\n<p><code>dao<\/code> \u2014 \u043b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 SQLAlchemy.<\/p>\n<\/li>\n<li>\n<p><code>static<\/code> \u2014 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0444\u043e\u0442\u043e \u0432\u0440\u0430\u0447\u0435\u0439).<\/p>\n<\/li>\n<li>\n<p><code>tg_bot<\/code> \u2014 \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 Telegram-\u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435 \u043f\u0430\u043f\u043a\u0438 app \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0442\u0440\u0438 \u0444\u0430\u0439\u043b\u0430:<\/p>\n<ol>\n<li>\n<p><code>async_client.py<\/code> \u2014 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 HTTP-\u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c (HTTPX).<\/p>\n<\/li>\n<li>\n<p><code>config.py<\/code> \u2014 \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>main.py<\/code> \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u0428\u0430\u0433 4: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439<\/strong><\/p>\n<p>\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0444\u0430\u0439\u043b <code>app\/config.py<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"python\">import os from typing import List  from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore from apscheduler.schedulers.asyncio import AsyncIOScheduler from pydantic_settings import BaseSettings, SettingsConfigDict   class Settings(BaseSettings):     BOT_TOKEN: str     ADMIN_IDS: List[int]     FORMAT_LOG: str = \"{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}\"     LOG_ROTATION: str = \"10 MB\"     DB_URL: str = 'sqlite+aiosqlite:\/\/\/data\/db.sqlite3'     STORE_URL: str = 'sqlite:\/\/\/data\/jobs.sqlite'     BASE_SITE: str     TG_API_SITE: str     FRONT_SITE: str      model_config = SettingsConfigDict(         env_file=os.path.join(os.path.dirname(os.path.abspath(__file__)), \"..\", \".env\")     )      def get_webhook_url(self) -&gt; str:         \"\"\"\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 URL \u0432\u0435\u0431\u0445\u0443\u043a\u0430.\"\"\"         return f\"{self.BASE_SITE}\/webhook\"      def get_tg_api_url(self) -&gt; str:         \"\"\"\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 URL Telegram API.\"\"\"         return f\"{self.TG_API_SITE}\/bot{self.BOT_TOKEN}\"   # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430 \u0437\u0430\u0434\u0430\u0447 settings = Settings() database_url = settings.DB_URL scheduler = AsyncIOScheduler(     jobstores={'default': SQLAlchemyJobStore(url=settings.STORE_URL)} ) <\/code><\/pre>\n<p>\u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0442\u0443\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>pydantic_settings<\/code> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0418\u0437 \u043d\u043e\u0432\u043e\u0433\u043e, \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 APScheduler. \u042d\u0442\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u0438 \u0438\u0445 \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c. \u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 APScheduler \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439 \u043e \u0437\u0430\u043f\u0438\u0441\u044f\u0445 \u043a \u0434\u043e\u043a\u0442\u043e\u0440\u0430\u043c \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p><strong>\u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0437\u0430\u0434\u0430\u0447.<\/strong> \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>SQLAlchemyJobStore<\/code>, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 SQLite (data\/jobs.sqlite). \u0427\u0430\u0449\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 Redis, \u043d\u043e \u044f, \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u044f, \u0440\u0435\u0448\u0438\u043b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u0434\u0430\u043d\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435.<\/p>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a.<\/strong> \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>AsyncIOScheduler<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u043d\u0430\u0448\u0435. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u0431\u0435\u0437 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e <code>APSCheduler<\/code> \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0432 \u0431\u043b\u043e\u043a\u0435 \u043f\u0440\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.<\/p>\n<p><strong>\u0428\u0430\u0433 5: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 HTTP-\u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/strong><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b app\/async_client.py:<\/p>\n<pre><code class=\"python\">import httpx from typing import Optional   class HTTPClientManager:     def __init__(self):         self._client: Optional[httpx.AsyncClient] = None      def get_client(self) -&gt; httpx.AsyncClient:         \"\"\"\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 HTTP-\u043a\u043b\u0438\u0435\u043d\u0442\u0430.\"\"\"         if self._client is None:             self._client = httpx.AsyncClient()         return self._client      async def close_client(self):         \"\"\"\u0417\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 HTTP-\u043a\u043b\u0438\u0435\u043d\u0442.\"\"\"         if self._client:             await self._client.aclose()             self._client = None   # \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f HTTP-\u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c http_client_manager = HTTPClientManager() <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u043d\u0430 \u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 \u0432\u0441\u0435\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0447\u0442\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 Telegram.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430. \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b API, \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c Telegram-\u0431\u043e\u0442\u0430.<\/p>\n<h3>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443 SQLAlchemy \u0438 Alembic<\/h3>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u0441 \u0432\u0430\u043c\u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0442\u0430\u0431\u043b\u0438\u0446 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 (\u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 SQLite). \u041f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043c\u043e\u0438\u043c\u0438 \u0441\u0442\u0430\u0442\u044c\u044f\u043c\u0438:<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/amvera\/articles\/849836\/\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 SQLAlchemy 2: \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0439 \u0433\u0430\u0439\u0434 \u043f\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435, \u043c\u043e\u0434\u0435\u043b\u044f\u043c, \u0441\u0432\u044f\u0437\u044f\u043c \u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Alembic.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/amvera\/articles\/850470\/\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 SQLAlchemy 2: \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0439 \u0433\u0430\u0439\u0434 \u043f\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u0441\u0435\u0441\u0441\u0438\u044f\u043c\u0438, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 Pydantic.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/amvera\/articles\/855740\/\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 SQLAlchemy 2: \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430, \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u044d\u0442\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u0432\u044b \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438, \u0441\u0432\u044f\u0437\u044f\u043c\u0438 \u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c\u0438. \u042f \u0431\u0443\u0434\u0443 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c, \u0447\u0442\u043e \u0432\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u043e\u0441\u043d\u043e\u0432\u0430\u043c\u0438 \u0438\u043b\u0438 \u0438\u0437\u0443\u0447\u0438\u043b\u0438 \u0438\u0445 \u0438\u0437 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432.<\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u0430\u043f\u043a\u0435 <code>app\/dao<\/code>. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0435\u0451 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439:<\/p>\n<pre><code class=\"css\">\u251c\u2500\u2500 dao\/ \u2502   \u251c\u2500\u2500 __init__.py                # \u041f\u0430\u043a\u0435\u0442\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u0432 \u2502   \u251c\u2500\u2500 database.py                # \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 SQLAlchemy \u2502   \u251c\u2500\u2500 models.py                  # \u041c\u043e\u0434\u0435\u043b\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u2502   \u251c\u2500\u2500 base.py                    # \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0411\u0414 \u2502   \u2514\u2500\u2500 session_maker_fast_api.py  # \u041a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0435\u0441\u0441\u0438\u0439 \u0432 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u0445 FastAPI<\/code><\/pre>\n<h3>\u0424\u0430\u0439\u043b database.py<\/h3>\n<p>\u0424\u0430\u0439\u043b <code>database.py<\/code> \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 SQLAlchemy \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439.<\/p>\n<pre><code class=\"python\">from sqlalchemy.orm import DeclarativeBase from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, create_async_engine, AsyncSession from app.config import database_url  engine = create_async_engine(url=database_url) async_session_maker = async_sessionmaker(engine, class_=AsyncSession)  class Base(AsyncAttrs, DeclarativeBase):     __abstract__ = True <\/code><\/pre>\n<ul>\n<li>\n<p><strong>engine<\/strong>: \u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>create_async_engine<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>async_session_maker<\/strong>: \u0424\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0441\u0435\u0441\u0441\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u043b\u0430\u0441\u0441 Base<\/strong>: \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<\/ul>\n<h3>\u0424\u0430\u0439\u043b app\/models.py<\/h3>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u0434\u043e\u043a\u0442\u043e\u0440\u0430, \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u044f\u0432\u043a\u0438. \u041e\u043f\u0438\u0448\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438:<\/p>\n<pre><code class=\"python\">from datetime import datetime from typing import Optional, List from sqlalchemy import Integer, Text, ForeignKey, DateTime, text from sqlalchemy.orm import Mapped, mapped_column, relationship from datetime import time, date from app.dao.database import Base   class User(Base):     __tablename__ = \"users\"      id: Mapped[int] = mapped_column(primary_key=True)     telegram_id: Mapped[int] = mapped_column(Integer, unique=True)     username: Mapped[str | None]     first_name: Mapped[str]     last_name: Mapped[str | None]      # Relationships     bookings: Mapped[List[\"Booking\"]] = relationship(back_populates=\"user\")   class Doctor(Base):     __tablename__ = \"doctors\"      id: Mapped[int] = mapped_column(primary_key=True)     first_name: Mapped[str]     last_name: Mapped[str]     patronymic: Mapped[Optional[str]]     special: Mapped[str]     specialization_id: Mapped[int] = mapped_column(ForeignKey(\"specializations.id\"), server_default=text(\"1\"))     work_experience: Mapped[int] = mapped_column(Integer, nullable=False)     experience: Mapped[str]     description: Mapped[str] = mapped_column(Text)     photo: Mapped[str]      # Relationships     bookings: Mapped[List[\"Booking\"]] = relationship(back_populates=\"doctor\")      specialization: Mapped[\"Specialization\"] = relationship(\"Specialization\", back_populates=\"doctors\",                                                             lazy=\"joined\")   class Specialization(Base):     __tablename__ = \"specializations\"      id: Mapped[int] = mapped_column(primary_key=True)     description: Mapped[str] = mapped_column(Text)     icon: Mapped[str]     label: Mapped[str]     specialization: Mapped[str]      doctors: Mapped[List[\"Doctor\"]] = relationship(back_populates=\"specialization\")   class Booking(Base):     __tablename__ = \"booking\"      id: Mapped[int] = mapped_column(primary_key=True)     doctor_id: Mapped[int] = mapped_column(ForeignKey(\"doctors.id\"))     user_id: Mapped[int] = mapped_column(ForeignKey(\"users.id\"))     day_booking: Mapped[date] = mapped_column(nullable=False)     time_booking: Mapped[time] = mapped_column(nullable=False)     booking_status: Mapped[str]     created_at: Mapped[datetime] = mapped_column(         DateTime,         default=datetime.utcnow,         nullable=False     )      # Relationships     doctor: Mapped[\"Doctor\"] = relationship(back_populates=\"bookings\")     user: Mapped[\"User\"] = relationship(back_populates=\"bookings\") <\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0447\u0438\u0442\u0430\u043b\u0438 \u043c\u043e\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u043e SQLAlchemy, \u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0432\u0441\u0451 \u043f\u043e\u043d\u044f\u0442\u043d\u043e. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0432\u044f\u0437\u0438 \u043c\u0435\u0436\u0434\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438 (relationship). \u041e\u043d\u0438 \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u044d\u0442\u0438\u043c\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043c \u044d\u0442\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c Alembic, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 \u0440\u0430\u043d\u0435\u0435.<\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Alembic \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0439 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>app<\/code>. \u0412 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u0432\u0432\u043e\u0434\u0438\u0442\u0435:<\/p>\n<pre><code class=\"bash\">cd app<\/code><\/pre>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c Alembic \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"bash\">alembic init -t async migration<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043f\u0430\u043f\u043a\u0430 <code>migration<\/code> \u0438 \u0444\u0430\u0439\u043b <code>alembic.ini<\/code>. \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u0435 <code>alembic.ini<\/code> \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u0430\u0439\u043b\u0430 alembic.ini<\/h4>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b <code>alembic.ini<\/code> \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0435 \u0441\u0442\u0440\u043e\u043a\u0443:<\/p>\n<pre><code class=\"1c\">script_location = migration<\/code><\/pre>\n<p>\u043d\u0430:<\/p>\n<pre><code class=\"1c\">script_location = app\/migration<\/code><\/pre>\n<p>\u042d\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438\u0437 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438.<\/p>\n<h4>\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 env.py \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043d\u0435\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b <code>app\/migration\/env.py<\/code>, \u0447\u0442\u043e\u0431\u044b Alembic \u043c\u043e\u0433 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0430\u0448\u0435\u0439 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445. \u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u0444\u0430\u0439\u043b \u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u0435 \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p><strong>\u0411\u044b\u043b\u043e<\/strong>:<\/p>\n<pre><code class=\"python\">import asyncio from logging.config import fileConfig from sqlalchemy import pool from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import async_engine_from_config from alembic import context  config = context.config  if config.config_file_name is not None:     fileConfig(config.config_file_name)  target_metadata = None <\/code><\/pre>\n<p><strong>\u0421\u0442\u0430\u043b\u043e<\/strong>:<\/p>\n<pre><code class=\"python\">import asyncio from logging.config import fileConfig from sqlalchemy import pool from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import async_engine_from_config from alembic import context from app.config import database_url from app.dao.database import Base from app.dao.models import User, Doctor, Specialization, Booking  config = context.config  config.set_main_option(\"sqlalchemy.url\", database_url) if config.config_file_name is not None:     fileConfig(config.config_file_name)  target_metadata = Base.metadata <\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u0432\u0448\u0443\u044e\u0441\u044f \u0447\u0430\u0441\u0442\u044c \u0444\u0430\u0439\u043b\u0430 \u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0439 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code class=\"bash\">cd ..\/<\/code><\/pre>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u0444\u0430\u0439\u043b \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438:<\/p>\n<pre><code class=\"bash\">alembic revision --autogenerate -m \"Initial revision\"<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"bash\">alembic upgrade head<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0444\u0430\u0439\u043b <code>db.sqlite3<\/code>, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>users<\/code>, <code>doctors<\/code>, <code>booking<\/code> \u0438 <code>specializations<\/code>.<\/p>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043a\u0442\u043e\u0440\u0430\u043c\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u00ab\u0437\u0430 \u043a\u0443\u043b\u0438\u0441\u0430\u043c\u0438\u00bb, \u0430 \u0441\u0435\u0439\u0447\u0430\u0441 \u0434\u0430\u043c \u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0434\u043e\u043a\u0442\u043e\u0440\u043e\u0432 \u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0439.<\/p>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0434\u043e\u043a\u0442\u043e\u0440\u043e\u0432:<\/h4>\n<pre><code class=\"json\">{   \"id\": 1,   \"first_name\": \"\u0418\u0432\u0430\u043d\",   \"patronymic\": \"\u0418\u0432\u0430\u043d\u043e\u0432\u0438\u0447\",   \"specialization_id\": 1,   \"experience\": \"\u043b\u0435\u0442\",   \"last_name\": \"\u0418\u0432\u0430\u043d\u043e\u0432\",   \"special\": \"\u0422\u0435\u0440\u0430\u043f\u0435\u0432\u0442\",   \"work_experience\": 15,   \"description\": \"\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0435 \u0438 \u043b\u0435\u0447\u0435\u043d\u0438\u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0431\u043e\u043b\u0435\u0437\u043d\u0435\u0439. \u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043a\u0443\u0440\u0441\u044b \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.\",   \"photo\": \"man1.jpg\" } <\/code><\/pre>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0442\u0443\u0442 \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0430 <strong>photo<\/strong>. \u0421\u043c\u044b\u0441\u043b \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 FastAPI \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0444\u043e\u0442\u043e, \u0430 \u0432 \u043a\u043e\u043b\u043e\u043d\u043a\u0435 <strong>photo<\/strong> \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435.<\/p>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/h4>\n<pre><code class=\"json\">{   \"id\": 1,   \"description\": \"\u0422\u0435\u0440\u0430\u043f\u0435\u0432\u0442\u044b \u043d\u0430\u0448\u0435\u0439 \u043a\u043b\u0438\u043d\u0438\u043a\u0438 \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u0432\u0430\u043c \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u0441 \u043e\u0431\u0449\u0438\u043c\u0438 \u0437\u0430\u0431\u043e\u043b\u0435\u0432\u0430\u043d\u0438\u044f\u043c\u0438, \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0430\u0442 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 \u043f\u043e \u043b\u0435\u0447\u0435\u043d\u0438\u044e \u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u0430\u043a\u0442\u0438\u043a\u0435. \u0417\u0430\u0431\u043e\u0442\u044c\u0442\u0435\u0441\u044c \u043e \u0441\u0432\u043e\u0435\u043c \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043f\u0440\u043e\u0444\u0435\u0441\u0441\u0438\u043e\u043d\u0430\u043b\u0430\u043c\u0438.\",   \"specialization\": \"\u0422\u0435\u0440\u0430\u043f\u0435\u0432\u0442\u044b\",   \"label\": \"\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0442\u0435\u0440\u0430\u043f\u0435\u0432\u0442\u0430\",   \"icon\": \"fas fa-user-md\" } <\/code><\/pre>\n<p>\u0422\u0443\u0442 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043b\u043e\u043d\u043a\u0430 <strong>icon<\/strong>. \u0422\u0430\u043c \u044f \u0445\u0440\u0430\u043d\u044e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0438\u043a\u043e\u043d\u043e\u043a Font Awesome. \u042d\u0442\u043e \u0442\u043e\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430.<\/p>\n<p>\u0422\u0430\u0431\u043b\u0438\u0446\u044b <strong>users<\/strong> \u0438 <strong>booking<\/strong> \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0432 \u00ab\u0431\u043e\u0435\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435\u00bb \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0432\u0441\u0451 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u043e \u0432 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c-\u043a\u0430\u043d\u0430\u043b\u0435 \u00ab<a href=\"https:\/\/t.me\/PythonPathMaster\">\u041b\u0435\u0433\u043a\u0438\u0439 \u043f\u0443\u0442\u044c \u0432 Python<\/a>\u00bb \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043a\u0430\u043a \u043f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u044d\u043a\u0435\u043d\u0434\u0430, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 10 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0439 \u0438 20 \u0434\u043e\u043a\u0442\u043e\u0440\u043e\u0432.<\/p>\n<h3>\u041f\u0438\u0448\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0432\u0430\u0436\u043d\u044b\u0445 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0432\u0441\u0435\u0433\u043e \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2014 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 <strong>BaseDao<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u044b\u0435 \u043a\u043e \u0432\u0441\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0445\u043e\u0434 \u0441 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u0432\u044b\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<p><strong>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/strong><\/p>\n<p>\u0412 \u043f\u0430\u043f\u043a\u0435 <code>app\/dao<\/code>, \u0432 \u0444\u0430\u0439\u043b\u0435 <code>base.py<\/code>, \u043c\u044b \u043e\u043f\u0438\u0448\u0435\u043c \u044d\u0442\u043e\u0442 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441. \u0412 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0430\u043f\u043a\u0430\u0445 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043f\u0430\u043f\u043a\u0435 <code>api<\/code>) \u0431\u0443\u0434\u0443\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u044b. \u041f\u0440\u0438\u0432\u0435\u0434\u0443 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430 <code>app\/dao\/base.py<\/code>, \u0447\u0442\u043e\u0431\u044b \u0432\u044b \u043f\u043e\u043d\u044f\u043b\u0438 \u043e\u0431\u0449\u0438\u0439 \u043f\u043e\u0434\u0445\u043e\u0434. \u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0444\u0430\u0439\u043b\u0430 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u043c\u043e\u0435\u043c <a href=\"https:\/\/t.me\/PythonPathMaster\">\u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c \u043a\u0430\u043d\u0430\u043b\u0435<\/a>.<\/p>\n<pre><code class=\"python\">from typing import List, Any, TypeVar, Generic from pydantic import BaseModel from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.future import select from sqlalchemy import update as sqlalchemy_update, delete as sqlalchemy_delete, func from loguru import logger from sqlalchemy.ext.asyncio import AsyncSession from app.dao.database import Base  # \u041e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u0442\u0438\u043f\u043e\u0432\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 T \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a Base T = TypeVar(\"T\", bound=Base)  class BaseDAO(Generic[T]):     model: type[T]      @classmethod     async def find_one_or_none_by_id(cls, data_id: int, session: AsyncSession):         # \u041d\u0430\u0439\u0442\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u043f\u043e ID         logger.info(f\"\u041f\u043e\u0438\u0441\u043a {cls.model.__name__} \u0441 ID: {data_id}\")         try:             query = select(cls.model).filter_by(id=data_id)             result = await session.execute(query)             record = result.scalar_one_or_none()             if record:                 logger.info(f\"\u0417\u0430\u043f\u0438\u0441\u044c \u0441 ID {data_id} \u043d\u0430\u0439\u0434\u0435\u043d\u0430.\")             else:                 logger.info(f\"\u0417\u0430\u043f\u0438\u0441\u044c \u0441 ID {data_id} \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430.\")             return record         except SQLAlchemyError as e:             logger.error(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u0438\u0441\u043a\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0441 ID {data_id}: {e}\")             raise      @classmethod     async def find_one_or_none(cls, session: AsyncSession, filters: BaseModel):         # \u041d\u0430\u0439\u0442\u0438 \u043e\u0434\u043d\u0443 \u0437\u0430\u043f\u0438\u0441\u044c \u043f\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c         filter_dict = filters.model_dump(exclude_unset=True)         logger.info(f\"\u041f\u043e\u0438\u0441\u043a \u043e\u0434\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 {cls.model.__name__} \u043f\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c: {filter_dict}\")         try:             query = select(cls.model).filter_by(**filter_dict)             result = await session.execute(query)             record = result.scalar_one_or_none()             if record:                 logger.info(f\"\u0417\u0430\u043f\u0438\u0441\u044c \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u043f\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c: {filter_dict}\")             else:                 logger.info(f\"\u0417\u0430\u043f\u0438\u0441\u044c \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u043f\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c: {filter_dict}\")             return record         except SQLAlchemyError as e:             logger.error(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u0438\u0441\u043a\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c {filter_dict}: {e}\")             raise      @classmethod     async def add(cls, session: AsyncSession, values: BaseModel):         # \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0434\u043d\u0443 \u0437\u0430\u043f\u0438\u0441\u044c         values_dict = values.model_dump(exclude_unset=True)         logger.info(f\"\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 {cls.model.__name__} \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438: {values_dict}\")         new_instance = cls.model(**values_dict)         session.add(new_instance)         try:             await session.flush()             logger.info(f\"\u0417\u0430\u043f\u0438\u0441\u044c {cls.model.__name__} \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430.\")         except SQLAlchemyError as e:             await session.rollback()             logger.error(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438: {e}\")             raise e         return new_instance <\/code><\/pre>\n<p>\u0412 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 <strong>BaseDAO<\/strong> \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u043d\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 (commit) \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0431\u0430\u0437\u0435. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u0438 \u0438 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043e\u0434\u043d\u0438\u043c \u043a\u043e\u043c\u043c\u0438\u0442\u043e\u043c \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438. \u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0446\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430.<\/p>\n<h3>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 BaseDAO<\/h3>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u043a\u043b\u0430\u0441\u0441, \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043e\u0442 <strong>BaseDAO<\/strong>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"python\">class UserDAO(BaseDAO[User]):     model = User <\/code><\/pre>\n<p>\u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e:<\/p>\n<pre><code class=\"python\">user_info = await UserDAO.find_one_or_none(session=session, filters=filters) <\/code><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0432 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b. \u0412\u0441\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u043e\u0442 <strong>BaseDao<\/strong> \u0431\u0443\u0434\u0443\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432 \u0444\u0430\u0439\u043b\u0435 <code>app\/api\/dao.py<\/code>.<\/p>\n<h3>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432<\/h3>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430 <code>app\/api\/dao.py<\/code>. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0438\u043c\u043f\u043e\u0440\u0442\u044b:<\/p>\n<pre><code class=\"python\">from datetime import date, timedelta, datetime, time, timezone from typing import List from fastapi import HTTPException from loguru import logger from sqlalchemy import select, and_, func from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import joinedload from app.dao.base import BaseDAO from app.dao.models import User, Specialization, Doctor, Booking <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043f\u0438\u0448\u0435\u043c \u0434\u0432\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u0430 \u0431\u0435\u0437 \u044d\u043a\u0441\u043a\u043b\u044e\u0437\u0438\u0432\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0432\u044b\u0437\u043e\u0432\u0430:<\/p>\n<pre><code class=\"python\">class SpecializationDAO(BaseDAO[Specialization]):     model = Specialization  class DoctorDAO(BaseDAO[Specialization]):     model = Doctor <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code class=\"python\">class UserDAO(BaseDAO[User]):     model = User      @classmethod     async def get_user_id(cls, session: AsyncSession, telegram_id: int) -&amp;gt; int | None:         query = select(cls.model.id).filter_by(telegram_id=telegram_id)         result = await session.execute(query)         return result.scalar_one_or_none() <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u0435\u0433\u043e <code>telegram_id<\/code>.<\/p>\n<h3>\u0420\u0430\u0437\u0431\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 BookingDAO<\/h3>\n<p>\u041e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u0430\u043c\u044b\u043c \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0431\u043e\u0440\u0430. \u0412\u043e\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441:<\/p>\n<pre><code class=\"python\">class BookingDAO(BaseDAO[Booking]):     model = Booking      @classmethod     async def count_user_booking(cls, session: AsyncSession, user_id: int) -&gt; int:         query = select(func.count()).where(cls.model.user_id == user_id)         result = await session.execute(query)         return result.scalar_one()      @classmethod     async def get_user_bookings_with_doctor_info(cls, session: AsyncSession, user_id: int):         query = (             select(cls.model)             .options(joinedload(cls.model.doctor))             .where(cls.model.user_id == user_id)             .order_by(cls.model.day_booking, cls.model.time_booking)         )         result = await session.execute(query)         result_draft = result.unique().scalars().all()         data_list = []         for info in result_draft:             data_list.append({                 \"id\": info.id,                 \"day_booking\": info.day_booking.strftime(\"%Y-%m-%d\"),                 \"time_booking\": info.time_booking.strftime(\"%H:%M\"),                 \"special\": info.doctor.special,                 \"doctor_full_name\": f\"{info.doctor.first_name} {info.doctor.last_name} {info.doctor.patronymic}\",             })         return data_list      @classmethod     def generate_working_hours(cls, start_hour=8, end_hour=20, step_minutes=30) -&amp;gt; List[str]:         \"\"\"\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0447\u0430\u0441\u043e\u0432 \u0441 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u043e\u043c\"\"\"         working_hours = []         current_time = datetime.strptime(f\"{start_hour}:00\", \"%H:%M\")         end_time = datetime.strptime(f\"{end_hour}:00\", \"%H:%M\")          while current_time &amp;lt;= end_time:             working_hours.append(current_time.strftime(\"%H:%M\"))             current_time += timedelta(minutes=step_minutes)          return working_hours[:-1]      @classmethod     async def get_available_slots(             cls,             session: AsyncSession,             doctor_id: int,             start_date: date     ) -&gt; dict[str, int | list[dict[str, str | int | list[str]]]]:         \"\"\"         \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0441\u043b\u043e\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0443 \u043d\u0430 \u043d\u0435\u0434\u0435\u043b\u044e \u0432\u043f\u0435\u0440\u0435\u0434, \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439.          Args:             session: AsyncSession - \u0441\u0435\u0441\u0441\u0438\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445             doctor_id: int - ID \u0432\u0440\u0430\u0447\u0430             start_date: date - \u0434\u0430\u0442\u0430 \u0437\u0430\u043a\u0430\u0437\u0430          Returns:             List[Dict[str, Union[str, List[str], int]]] - \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043d\u0435\u0439 \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0442\u0430\u043c\u0438         \"\"\"         try:             # \u0421\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0430\u0442\u0443 \u0441 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u043d\u0435\u0434\u0435\u043b\u0438 (\u043f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a)             start_of_week = start_date - timedelta(days=start_date.weekday())             end_of_week = start_of_week + timedelta(days=5)              # \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0431\u0440\u043e\u043d\u0438             query = select(cls.model).where(                 and_(                     cls.model.doctor_id == doctor_id,                     cls.model.day_booking &amp;gt;= start_of_week,                     cls.model.day_booking &amp;lt;= end_of_week                 )             )             result = await session.execute(query)             existing_bookings = result.scalars().all()              # \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0447\u0430\u0441\u043e\u0432             working_hours = cls.generate_working_hours()              # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043d\u044f\u0442\u044b\u0445 \u0441\u043b\u043e\u0442\u043e\u0432             booked_slots = {                 (                     booking.day_booking.isoformat(),                     booking.time_booking.strftime(\"%H:%M\")                 )                 for booking in existing_bookings             }              # \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0434\u043d\u0435\u0439 \u043d\u0435\u0434\u0435\u043b\u0438 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c             week_days_rus = [\"\u041f\u043e\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u0438\u043a\", \"\u0412\u0442\u043e\u0440\u043d\u0438\u043a\", \"\u0421\u0440\u0435\u0434\u0430\", \"\u0427\u0435\u0442\u0432\u0435\u0440\u0433\", \"\u041f\u044f\u0442\u043d\u0438\u0446\u0430\", \"\u0421\u0443\u0431\u0431\u043e\u0442\u0430\"]              # \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442             available_slots = []              for day_offset in range(6):                 current_date = start_of_week + timedelta(days=day_offset)                 current_date_str = current_date.isoformat()                 day_name_rus = week_days_rus[day_offset]                  # \u0415\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0434\u0430\u0442\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0435\u0439, \u0441\u043b\u043e\u0442\u044b \u043f\u0443\u0441\u0442\u044b\u0435                 day_slots = []                 if current_date &amp;gt;= datetime.now().date():                     for time_str in working_hours:                         is_available = (current_date_str, time_str) not in booked_slots                          if current_date == datetime.now().date():                             slot_time = datetime.strptime(time_str, \"%H:%M\").time()                             if slot_time &amp;lt;= datetime.now().time():                                 is_available = False                          if is_available:                             day_slots.append(time_str)                  # \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442                 available_slots.append({                     \"day\": day_name_rus,                     \"date\": current_date_str,                     \"slots\": day_slots,                     \"total_slots\": len(day_slots)                 })              # \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u0434\u043d\u0438 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0439 \u0434\u0430\u0442\u044b             filter_data = [                 day for day in available_slots if                 start_of_week &amp;lt;= datetime.fromisoformat(day[\"date\"]).date() &amp;lt;= end_of_week             ]              return {\"days\": filter_data, \"total_week_slots\": sum(day[\"total_slots\"] for day in filter_data)}          except Exception as e:             # \u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438             logger.error(f\"Error in get_available_slots: {str(e)}\")             raise HTTPException(                 status_code=500,                 detail=\"Error while getting available slots\"             )      @classmethod     async def book_appointment(             cls,             session: AsyncSession,             doctor_id: int,             user_id: int,             day_booking: date,             time_booking: time     ) -&gt; Booking:         \"\"\"         \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438.          Args:             session: AsyncSession - \u0441\u0435\u0441\u0441\u0438\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445             doctor_id: int - ID \u0432\u0440\u0430\u0447\u0430             user_id: int - ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f             day_booking: date - \u0434\u0430\u0442\u0430 \u0431\u0440\u043e\u043d\u0438             time_booking: time - \u0432\u0440\u0435\u043c\u044f \u0431\u0440\u043e\u043d\u0438          Returns:             Booking - \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c         \"\"\"         try:             today = date.today()             logger.info(f\"today: {today}, day_booking: {day_booking}\")             if day_booking &amp;lt; date.today():                 raise HTTPException(                     status_code=400,                     detail=\"\u0414\u0430\u0442\u0430 \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0435\u0439 \u0434\u0430\u0442\u044b\"                 )              # \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u043c \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435 \u0438 \u0441 \u0448\u0430\u0433\u043e\u043c \u0432 30 \u043c\u0438\u043d\u0443\u0442             if not (time(8, 0) &amp;lt;= time_booking &amp;lt;= time(19, 30)):                 raise HTTPException(                     status_code=400,                     detail=\"\u0412\u0440\u0435\u043c\u044f \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043c\u0435\u0436\u0434\u0443 08:00 \u0438 19:30\"                 )             logger.info(f\"\u041c\u0418\u041d\u0423\u0422\u042b: {time_booking.minute}\")             if time_booking.minute not in [0, 30]:                 raise HTTPException(                     status_code=400,                     detail=\"\u0412\u0440\u0435\u043c\u044f \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043d\u0430 \u0446\u0435\u043b\u044b\u0439 \u0447\u0430\u0441 \u0438\u043b\u0438 \u043d\u0430 30 \u043c\u0438\u043d\u0443\u0442\"                 )              # \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0441\u043b\u043e\u0442 \u043d\u0435 \u0437\u0430\u043d\u044f\u0442             query = select(cls.model).where(                 and_(                     cls.model.doctor_id == doctor_id,                     cls.model.day_booking == day_booking,                     cls.model.time_booking == time_booking                 )             )             result = await session.execute(query)             existing_booking = result.scalar_one_or_none()              if existing_booking:                 raise HTTPException(                     status_code=400,                     detail=\"\u0421\u043b\u043e\u0442 \u0443\u0436\u0435 \u0437\u0430\u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\"                 )              # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0431\u0440\u043e\u043d\u044c             new_booking = cls.model(                 doctor_id=doctor_id,                 user_id=user_id,                 day_booking=day_booking,                 time_booking=time_booking,                 booking_status=\"confirmed\",  # \u0421\u0442\u0430\u0442\u0443\u0441 \u0431\u0440\u043e\u043d\u0438                 created_at=datetime.now(timezone.utc)  # \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043e             )             session.add(new_booking)             await session.flush()             return new_booking          except IntegrityError as e:             logger.error(f\"IntegrityError in book_appointment: {str(e)}\")             await session.rollback()             raise HTTPException(                 status_code=500,                 detail=\"\u041e\u0448\u0438\u0431\u043a\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0431\u0440\u043e\u043d\u0438\"             ) <\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>BookingDAO<\/code> \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 <code>BaseDAO<\/code> \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u043d\u0430 \u043f\u0440\u0438\u0435\u043c \u043a \u0432\u0440\u0430\u0447\u0443. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0433\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e.<\/p>\n<pre><code class=\"python\">class BookingDAO(BaseDAO[Booking]):     model = Booking <\/code><\/pre>\n<h4>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043b\u0430\u0441\u0441\u0430<\/h4>\n<ol>\n<li>\n<p><strong>count_user_booking<\/strong><\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">@classmethod async def count_user_booking(cls, session: AsyncSession, user_id: int) -&gt; int:     query = select(func.count()).where(cls.model.user_id == user_id)     result = await session.execute(query)     return result.scalar_one() <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 SQLAlchemy \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 <code>Booking<\/code>, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c <code>user_id<\/code>.<\/p>\n<ol start=\"2\">\n<li>\n<p><strong>get_user_bookings_with_doctor_info<\/strong><\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">@classmethod async def get_user_bookings_with_doctor_info(cls, session: AsyncSession, user_id: int): <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0432\u0440\u0430\u0447\u0430\u0445, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043e\u043d\u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u044b. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>joinedload<\/code>, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c N+1 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0432\u0440\u0430\u0447\u0430\u0445.<\/p>\n<ol start=\"3\">\n<li>\n<p><strong>generate_working_hours<\/strong><\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">@classmethod def generate_working_hours(cls, start_hour=8, end_hour=20, step_minutes=30) -&gt; List[str]:     \"\"\"\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0447\u0430\u0441\u043e\u0432 \u0441 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u043e\u043c\"\"\" <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0447\u0430\u0441\u043e\u0432 \u0432\u0440\u0430\u0447\u0430 \u0441 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c \u0448\u0430\u0433\u043e\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u0436\u0434\u044b\u0435 30 \u043c\u0438\u043d\u0443\u0442). \u042d\u0442\u043e \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0442\u043e\u0432 \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<ol start=\"4\">\n<li>\n<p><strong>get_available_slots<\/strong><\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">@classmethod async def get_available_slots(         cls,         session: AsyncSession,         doctor_id: int,         start_date: date ) -&amp;gt; dict[str, int | list[dict[str, str | int | list[str]]]]:     \"\"\"     \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0441\u043b\u043e\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0443 \u043d\u0430 \u043d\u0435\u0434\u0435\u043b\u044e \u0432\u043f\u0435\u0440\u0435\u0434, \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439.     \"\"\"<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0441\u043b\u043e\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0443 \u043d\u0430 \u043d\u0435\u0434\u0435\u043b\u044e \u0432\u043f\u0435\u0440\u0435\u0434. \u041e\u043d \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0431\u0440\u043e\u043d\u0438 \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u043e\u0432.<\/p>\n<ol start=\"5\">\n<li>\n<p><strong>book_appointment<\/strong><\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">@classmethod async def book_appointment(         cls,         session: AsyncSession,         doctor_id: int,         user_id: int,         day_booking: date,         time_booking: time ) -&gt; Booking:     \"\"\"     \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438.     \"\"\"<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430 \u043f\u0440\u0438\u0435\u043c. \u041e\u043d \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043d\u043e\u0432\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043a\u043b\u0430\u0441\u0441 BookingDAO \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u043d\u0430 \u043f\u0440\u0438\u0435\u043c \u043a \u0432\u0440\u0430\u0447\u0443. \u041e\u043d \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0437\u0430\u043f\u0438\u0441\u044f\u0445 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432\u0440\u0430\u0447\u0435\u0439, \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0447\u0438\u0445 \u0447\u0430\u0441\u043e\u0432 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0442\u0430\u043c\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b\u0438 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e API \u043c\u0435\u0442\u043e\u0434\u043e\u0432.<\/p>\n<h2>\u041f\u0438\u0448\u0435\u043c API \u043c\u0435\u0442\u043e\u0434\u044b<\/h2>\n<p>\u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043f\u0430\u043f\u043a\u043e\u0439 <code>app\/api<\/code>. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043d\u0435\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><code>api\/schemas.py<\/code>: \u0444\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 Pydantic (\u0441\u0445\u0435\u043c\u044b) \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>api\/router.py<\/code>: \u0444\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 API-\u043c\u0435\u0442\u043e\u0434\u044b.<\/p>\n<\/li>\n<\/ul>\n<h3>\u0421\u0445\u0435\u043c\u044b \u0432 \u0444\u0430\u0439\u043b\u0435 api\/schemas.py<\/h3>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0444\u0430\u0439\u043b\u0430 <code>api\/schemas.py<\/code>. \u0422\u0430\u043c \u043c\u044b \u043e\u043f\u0438\u0448\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u0441\u0445\u0435\u043c\u044b \u043a\u0430\u043a \u0434\u043b\u044f \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430, \u0442\u0430\u043a \u0438 \u0434\u043b\u044f \u0441\u0430\u043c\u043e\u0433\u043e API-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"python\">from datetime import date, time from typing import List, Dict from pydantic import BaseModel, ConfigDict  class BookingRequest(BaseModel):     doctor_id: int     user_id: int     day_booking: date     time_booking: time  class TelegramIDModel(BaseModel):     telegram_id: int      model_config = ConfigDict(from_attributes=True)  class SpecIDModel(BaseModel):     specialization_id: int  class UserModel(TelegramIDModel):     username: str | None     first_name: str | None     last_name: str | None  class BookingSlot(BaseModel):     time: str     isAvailable: bool  class BookingWeek(BaseModel):     week: Dict[str, List[BookingSlot]] <\/code><\/pre>\n<h4>\u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u0435 \u043f\u043e \u043c\u043e\u0434\u0435\u043b\u044f\u043c<\/h4>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u0434\u0435 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0435\u043b\u0435\u0439:<\/p>\n<ul>\n<li>\n<p><strong>BookingRequest<\/strong>: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u043a \u0432\u0440\u0430\u0447\u0443, \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0432\u0440\u0430\u0447\u0430 \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0430\u0442\u0443 \u0438 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>TelegramIDModel<\/strong>: \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 Telegram.<\/p>\n<\/li>\n<li>\n<p><strong>SpecIDModel<\/strong>: \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>UserModel<\/strong>: \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 <code>TelegramIDModel<\/code>, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0438\u043c\u0435\u043d\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>BookingSlot<\/strong>: \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u043b\u043e\u0442 \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>BookingWeek<\/strong>: \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0441\u043b\u043e\u0442\u0430\u0445 \u043d\u0430 \u043d\u0435\u0434\u0435\u043b\u044e.<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u0444\u0430\u0439\u043b\u0443 <code>app\/api\/router.py<\/code>.<\/p>\n<h3>\u0418\u043c\u043f\u043e\u0440\u0442\u044b \u0432 \u0444\u0430\u0439\u043b\u0435 app\/api\/router.py<\/h3>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u0432:<\/p>\n<pre><code class=\"python\">from datetime import date, datetime, timedelta from fastapi import APIRouter, Depends, HTTPException from loguru import logger from sqlalchemy.ext.asyncio import AsyncSession from app.api.dao import SpecializationDAO, DoctorDAO, BookingDAO, UserDAO from app.api.schemas import SpecIDModel, BookingRequest from app.dao.session_maker_fast_api import db from app.tg_bot.scheduler_task import schedule_appointment_notification import pytz <\/code><\/pre>\n<p>\u041f\u043e\u043a\u0430 \u043d\u0430 \u0438\u043c\u043f\u043e\u0440\u0442 <code>schedule_appointment_notification<\/code> \u043d\u0435 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0437\u0436\u0435. \u0410 \u0432\u043e\u0442 \u0447\u0442\u043e \u043d\u0430\u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u2013 \u044d\u0442\u043e \u0441\u0442\u0440\u043e\u043a\u0430:<\/p>\n<pre><code class=\"python\">from app.dao.session_maker_fast_api import db <\/code><\/pre>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u043f\u043e\u0440\u0442\u0443 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 FastAPI. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u0442\u043e \u0441\u043c\u044b\u0441\u043b \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u044f\u0441\u044c \u043a \u043d\u0430\u0448\u0438\u043c \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430\u043c, \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u2013 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0435\u0441\u0441\u0438\u0438.<\/p>\n<h3>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 app\/dao\/session_maker_fast_api.py<\/h3>\n<pre><code class=\"python\">from typing import AsyncGenerator from sqlalchemy.ext.asyncio import AsyncSession from app.dao.database import async_session_maker  class DatabaseSession:     @staticmethod     async def get_session(commit: bool = False) -&amp;gt; AsyncGenerator[AsyncSession, None]:         async with async_session_maker() as session:             try:                 yield session                 if commit:                     await session.commit()             except Exception:                 await session.rollback()                 raise             finally:                 await session.close()      @staticmethod     async def get_db() -&amp;gt; AsyncGenerator[AsyncSession, None]:         \"\"\"Dependency \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0435\u0441\u0441\u0438\u0438 \u0431\u0435\u0437 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430\"\"\"         async for session in DatabaseSession.get_session(commit=False):             yield session      @staticmethod     async def get_db_with_commit() -&amp;gt; AsyncGenerator[AsyncSession, None]:         \"\"\"Dependency \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0435\u0441\u0441\u0438\u0438 \u0441 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043a\u043e\u043c\u043c\u0438\u0442\u043e\u043c\"\"\"         async for session in DatabaseSession.get_session(commit=True):             yield session  # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0430 db = DatabaseSession() <\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u0442\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0435\u0433\u043e \u0441\u043c\u044b\u0441\u043b \u2013 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0434\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430:<\/p>\n<ul>\n<li>\n<p><strong>get_db<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0435\u0441\u0441\u0438\u044e \u0431\u0435\u0437 \u043a\u043e\u043c\u043c\u0438\u0442\u0430 (\u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414 \u0431\u0435\u0437 \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0439).<\/p>\n<\/li>\n<li>\n<p><strong>get_db_with_commit<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043a\u043e\u043c\u043c\u0438\u0442 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 FastAPI.<\/p>\n<\/li>\n<\/ul>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/h4>\n<pre><code class=\"python\">@router.get(\"\/items\") async def get_items(session: AsyncSession = Depends(db.get_db)):     # \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0435\u0441\u0441\u0438\u044e \u0431\u0435\u0437 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430     ...  @router.post(\"\/items\") async def create_item(session: AsyncSession = Depends(db.get_db_with_commit)):     # \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0435\u0441\u0441\u0438\u044e \u0441 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043a\u043e\u043c\u043c\u0438\u0442\u043e\u043c     ... <\/code><\/pre>\n<h3>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0444\u0430\u0439\u043b\u0443 api\/router.py<\/h3>\n<p>\u041f\u043e\u0434\u043a\u0438\u043d\u0435\u043c \u043c\u043e\u0441\u043a\u043e\u0432\u0441\u043a\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0440\u043e\u0443\u0442\u0435\u0440:<\/p>\n<pre><code class=\"python\">MOSCOW_TZ = pytz.timezone(\"Europe\/Moscow\") router = APIRouter()<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b. \u0421\u0430\u043c\u0438 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c\u0438 \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043b\u043e\u0433\u0438\u043a\u0438 \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u0437\u0430\u044f\u0432\u043a\u0438. \u041d\u0430\u0447\u043d\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c:<\/p>\n<h4>\u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b API<\/h4>\n<pre><code class=\"python\">@router.get(\"\/specialists\") async def get_specialists(session: AsyncSession = Depends(db.get_db)):     return await SpecializationDAO.find_all(session=session) <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043a\u043b\u0430\u0441\u0441\u0430 <code>BaseDao<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0437 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u0414\u043b\u044f \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u0432 \u00ab\u0431\u043e\u0435\u0432\u043e\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435\u00bb \u043e\u0431\u044b\u0447\u043d\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c Pydantic.<\/p>\n<pre><code class=\"python\">@router.get(\"\/doctors\/{spec_id}\") async def get_doctors_spec(spec_id: int, session: AsyncSession = Depends(db.get_db)):     return await DoctorDAO.find_all(session=session,                                     filters=SpecIDModel(specialization_id=spec_id)) <\/code><\/pre>\n<p>\u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 ID \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u043a\u0442\u043e\u0440\u043e\u0432 \u043f\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0442\u0435\u0440\u0430\u043f\u0435\u0432\u0442\u043e\u0432).<\/p>\n<pre><code class=\"python\">@router.get(\"\/doctor\/{doctor_id}\") async def get_doctor_by_id(doctor_id: int, session: AsyncSession = Depends(db.get_db)):     return await DoctorDAO.find_one_or_none_by_id(session=session, data_id=doctor_id) <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u043b\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u0434\u043e\u043a\u0442\u043e\u0440\u0443, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044f \u0435\u0433\u043e ID.<\/p>\n<pre><code class=\"python\">@router.get(\"\/booking\/available-slots\/{doctor_id}\") async def get_available_slots(         doctor_id: int,         start_date: date,         session: AsyncSession = Depends(db.get_db) ):     return await BookingDAO.get_available_slots(session=session, doctor_id=doctor_id, start_date=start_date) <\/code><\/pre>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u043c\u0435\u0442\u043e\u0434\u0443 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0445 \u0441\u043b\u043e\u0442\u0430\u0445 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0434\u043e\u043a\u0442\u043e\u0440\u0443 \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0434\u0435\u043d\u044c. \u041b\u043e\u0433\u0438\u043a\u0443 \u043c\u044b \u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>BookingDAO<\/code>.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u0438\u043d \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u043d\u0430\u0448\u0435\u0433\u043e API \u0434\u043b\u044f \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u043b\u043e\u0433\u0438\u043a\u0443 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u2014 \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 APSCheduler \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u0430\u0434\u0430\u0447 \u043d\u0430 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<h4>\u041e\u0431\u0449\u0438\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430<\/h4>\n<p>\u041e\u0431\u0449\u0438\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0431\u0443\u0434\u0435\u0442 \u0441\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443:<\/p>\n<ol>\n<li>\n<p>\u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0440\u044f\u0434\u0430 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443.<\/p>\n<\/li>\n<\/ol>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f APSCheduler \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0448 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b \u0441\u0432\u043e\u044e \u0440\u0430\u0431\u043e\u0442\u0443. \u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0441 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435\u043c \u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u043b\u044f\u0436\u0435\u0442 \u0443\u0436\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0443 APSCheduler.<\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0443 \u0434\u043b\u044f \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438, \u043a\u043e\u0433\u0434\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043b\u043e\u0433\u0438\u043a\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c \u0431\u043e\u0442\u0430.<\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c \u0431\u043e\u0442\u0430 \u043d\u0430 FastAPI + HTTPX<\/h3>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c \u0431\u043e\u0442\u0430 \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 Aiogram 3, \u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0432\u0441\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e. \u0412 \u044d\u0442\u043e\u043c \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0433\u0443\u0442 FastAPI \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 HTTPX. \u0412\u0441\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>app\/tg_bot<\/code>.<\/p>\n<h4>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h4>\n<p>\u0421\u0440\u0430\u0437\u0443 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441 \u043f\u0443\u0441\u0442\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438:<\/p>\n<pre><code class=\"css\">\u251c\u2500\u2500 tg_bot\/ \u2502   \u251c\u2500\u2500 handlers.py            # \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0431\u043e\u0442\u0430 (\u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \/start \u0438 \u0442.\u0434.) \u2502   \u251c\u2500\u2500 kbs.py                 # \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u0431\u043e\u0442\u0430 \u2502   \u251c\u2500\u2500 methods.py             # \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0431\u043e\u0442\u0430 (\u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 callback \u0438 \u0442.\u0434.) \u2502   \u251c\u2500\u2500 router.py              # \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0431\u043e\u0442\u0430 \u2502   \u2514\u2500\u2500 scheduler_task.py       # \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e <\/code><\/pre>\n<p>\u0417\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u043b\u043e\u0433\u0438\u043a\u0443 \u0431\u043e\u0442\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0441 \u0431\u043e\u0442\u043e\u043c. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0435 \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u0442\u0435\u043c\u0435 \u0441\u0430\u043c\u043e\u043f\u0438\u0441\u043d\u044b\u0445 \u0431\u043e\u0442\u043e\u0432, \u0441\u0435\u0439\u0447\u0430\u0441 \u043a\u0440\u0430\u0442\u043a\u043e \u043f\u0440\u043e\u0431\u0435\u0436\u0438\u043c\u0441\u044f \u043f\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c \u0438 \u0441\u0443\u0442\u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u0430.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0442\u043e \u043f\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441 \u044f \u043c\u043e\u0433\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e, \u0433\u0434\u0435 \u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u043e\u0442\u043e\u0432 \u0434\u043b\u044f Telegram \u0431\u0435\u0437 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0438 \u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434.<\/p>\n<h4>\u041a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b<\/h4>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440:<\/p>\n<pre><code class=\"python\">from app.config import settings  main_kb = [     [{\"text\": \"\ud83d\udcc5 \u041c\u043e\u0438 \u0437\u0430\u043f\u0438\u0441\u0438\", \"callback_data\": \"booking\"}],     [{\"text\": \"\ud83d\udd16 \u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f\", \"web_app\": {\"url\": f\"{settings.FRONT_SITE}\"}}],     [{\"text\": \"\u2139\ufe0f \u041e \u043d\u0430\u0441\", \"callback_data\": \"about_us\"}] ]  back_kb = [     [{\"text\": \"\ud83c\udfe0 \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\", \"callback_data\": \"home\"}],     [{\"text\": \"\ud83d\udd16 \u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f\", \"web_app\": {\"url\": f\"{settings.FRONT_SITE}\"}}] ]  def generate_kb_profile(user_db_id: int, count_booking: int):     kb_profile = [         [{\"text\": \"\ud83c\udfe0 \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\", \"callback_data\": \"home\"}],         [{\"text\": \"\ud83d\udd16 \u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f\", \"web_app\": {\"url\": f\"{settings.FRONT_SITE}\"}}]     ]     if count_booking &amp;gt; 0:         kb_profile.append([{\"text\": f\"\ud83d\udd12 \u041c\u043e\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 ({count_booking})\", \"callback_data\": f\"my_booking_{user_db_id}\"}])     return kb_profile <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430, \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430 \u00ab\u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\u00bb \u0438 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u0432 \u0431\u043e\u0442\u0435. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u043b\u0430\u0439\u043d-\u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b.<\/p>\n<h4>\u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043f\u0438\u0448\u0435\u043c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>tg_bot\/methods.py<\/code>.<\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0438\u043c\u043f\u043e\u0440\u0442\u044b:<\/p>\n<pre><code class=\"python\">from datetime import datetime from httpx import AsyncClient from app.config import settings <\/code><\/pre>\n<p><code>AsyncClient<\/code> \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u043b\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0439. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u0432.<\/p>\n<pre><code class=\"python\">async def bot_send_message(client: AsyncClient, chat_id: int, text: str, kb: list | None = None):     send_data = {\"chat_id\": chat_id, \"text\": text, \"parse_mode\": \"HTML\"}     if kb:         send_data[\"reply_markup\"] = {\"inline_keyboard\": kb}     await client.post(f\"{settings.get_tg_api_url()}\/sendMessage\", json=send_data) <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0441 \u0438\u043d\u043b\u0430\u0439\u043d \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043e\u0439 \u0438\u043b\u0438 \u0431\u0435\u0437 \u043d\u0435\u0435. \u0412 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u043b\u044f\u043b\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>bot.send_message<\/code> \u0438\u0437 Aiogram 3.<\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f Aiogram 3, \u0442\u043e \u0432 <a href=\"https:\/\/habr.com\/ru\/users\/yakvenalex\/publications\/articles\/\">\u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0444\u0438\u043b\u0435 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/a> \u0435\u0441\u0442\u044c \u043e\u043a\u043e\u043b\u043e \u0434\u0435\u0441\u044f\u0442\u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0439, \u043f\u043e\u0441\u0432\u044f\u0449\u0451\u043d\u043d\u044b\u0445 \u044d\u0442\u043e\u043c\u0443 Python-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 Telegram-\u0431\u043e\u0442\u043e\u0432. \u0412 \u0441\u0432\u043e\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0432\u0441\u0435 \u0430\u0441\u043f\u0435\u043a\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430.<\/p>\n<pre><code class=\"python\">async def call_answer(client: AsyncClient, callback_query_id: int, text: str):     await client.post(f\"{settings.get_tg_api_url()}\/answerCallbackQuery\", json={         \"callback_query_id\": callback_query_id,         \"text\": text     }) <\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 callback. \u0410\u043d\u0430\u043b\u043e\u0433 <code>call.answer()<\/code> \u0438\u0437 Aiogram 3.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0438\u0434\u0443\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0441 f-\u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438 \u0438 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043f\u043e \u0437\u0430\u043f\u0438\u0441\u0438. \u0412\u043e\u0442 \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code class=\"python\">def format_appointment(appointment, start_text=\"\ud83d\uddd3 &lt;b&gt;\u0417\u0430\u043f\u0438\u0441\u044c \u043d\u0430 \u043f\u0440\u0438\u0435\u043c&lt;\/b&gt;\"):     appointment_date = datetime.strptime(appointment['day_booking'], '%Y-%m-%d').strftime('%d.%m.%Y')     return f\"\"\" {start_text}  \ud83d\udcc5 \u0414\u0430\u0442\u0430: {appointment_date} \ud83d\udd52 \u0412\u0440\u0435\u043c\u044f: {appointment['time_booking']} \ud83d\udc68\u200d\u2695\ufe0f \u0412\u0440\u0430\u0447: {appointment['doctor_full_name']} \ud83c\udfe5 \u0421\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f: {appointment['special']}  \u2139\ufe0f \u041d\u043e\u043c\u0435\u0440 \u0437\u0430\u043f\u0438\u0441\u0438: {appointment['id']}  \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0435 \u0437\u0430 10-15 \u043c\u0438\u043d\u0443\u0442 \u0434\u043e \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \"\"\" <\/code><\/pre>\n<h4>\u0425\u0435\u043d\u0434\u043b\u0435\u0440\u044b \u0431\u043e\u0442\u0430<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u044b \u0431\u043e\u0442\u0430 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>tg_bot\/handlers.py<\/code>. \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0438\u043c\u043f\u043e\u0440\u0442\u044b:<\/p>\n<pre><code class=\"python\">from httpx import AsyncClient from app.api.dao import UserDAO, BookingDAO from app.api.schemas import TelegramIDModel, UserModel from app.tg_bot.kbs import back_kb, main_kb, generate_kb_profile from app.tg_bot.methods import call_answer, bot_send_message, get_greeting_text, get_about_text, get_booking_text, format_appointment <\/code><\/pre>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u044b\u0439 \u0445\u0435\u043d\u0434\u043b\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>\/start<\/code>:<\/p>\n<pre><code class=\"python\">async def cmd_start(client: AsyncClient, session, user_info):     user_in_db = await UserDAO.find_one_or_none(session=session, filters=TelegramIDModel(telegram_id=user_info[\"id\"]))      if not user_in_db:         # \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f         values = UserModel(             telegram_id=user_info[\"id\"],             username=user_info.get(\"username\"),             first_name=user_info.get(\"first_name\"),             last_name=user_info.get(\"last_name\")         )         await UserDAO.add(session=session, values=values)      greeting_message = get_greeting_text(user_info.get(\"first_name\"))     await bot_send_message(client, user_info[\"id\"], greeting_message, main_kb) <\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b:<\/p>\n<ul>\n<li>\n<p><strong>client<\/strong>: \u043a\u043b\u0438\u0435\u043d\u0442 (\u0441\u0435\u0441\u0441\u0438\u044f), \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u0430\u044f \u0441 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>session<\/strong>: \u0441\u0435\u0441\u0441\u0438\u044f \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p><strong>user_info<\/strong>: \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0438\u0434\u0435\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u0435\u0433\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"python\">async def handler_back_home(client: AsyncClient, callback_query_id: int, chat_id: int):     await call_answer(client, callback_query_id, \"\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\")     await bot_send_message(client, chat_id, \"\u0412\u044b \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435!\", main_kb) <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\u00bb.<\/p>\n<pre><code class=\"python\">async def handler_about_us(client: AsyncClient, callback_query_id: int, chat_id: int):     await call_answer(client, callback_query_id, \"\u041e \u043d\u0430\u0441\")     about_us_text = get_about_text()     await bot_send_message(client, chat_id, about_us_text, back_kb) <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0442\u0435\u043a\u0441\u0442 \u00ab\u041e \u043d\u0430\u0441\u00bb.<\/p>\n<pre><code class=\"python\">async def handler_my_appointments(client: AsyncClient, callback_query_id: int, chat_id: int, session):     await call_answer(client, callback_query_id, \"\u0412\u0430\u0448\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0430\u043c\")     db_user_id = await UserDAO.get_user_id(session=session, telegram_id=chat_id)     appointment_count = await BookingDAO.count_user_booking(session=session, user_id=db_user_id)     message_text = get_booking_text(appointment_count)     keyboard = generate_kb_profile(db_user_id, appointment_count)     await bot_send_message(client, chat_id, message_text, kb=keyboard) <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041c\u043e\u0438 \u0437\u0430\u043f\u0438\u0441\u0438\u00bb. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u043c \u043d\u0430 callback \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<pre><code class=\"python\">async def handler_my_appointments_all(client: AsyncClient,                                       callback_query_id: int,                                       chat_id: int,                                       user_db_id: int,                                       session):     await call_answer(client, callback_query_id, \"\u0412\u0430\u0448\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0430\u043c (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e)\")     appointments = await BookingDAO.get_user_bookings_with_doctor_info(session=session, user_id=user_db_id)      for appointment in appointments:         await bot_send_message(client, chat_id, format_appointment(appointment))      await bot_send_message(client, chat_id, \"\u042d\u0442\u043e \u0432\u0441\u0435 \u0432\u0430\u0448\u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438.\", main_kb) <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0445\u0435\u043d\u0434\u043b\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u0432\u0441\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044f\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u0432\u044b\u0448\u0435, \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Aiogram 3 \u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u0430\u043a \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<h4>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 API-\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0448 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 API-\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>tg_bot\/router.py<\/code>.<\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0438\u043c\u043f\u043e\u0440\u0442\u044b:<\/p>\n<pre><code class=\"python\">from fastapi import APIRouter, Request, Depends from sqlalchemy.ext.asyncio import AsyncSession from app.async_client import http_client_manager from app.dao.session_maker_fast_api import db from app.tg_bot.handlers import cmd_start, handler_my_appointments,\\      handler_about_us,\\      handler_back_home,\\      handler_my_appointments_all <\/code><\/pre>\n<p>\u0418\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c \u0440\u043e\u0443\u0442\u0435\u0440:<\/p>\n<pre><code class=\"python\">router = APIRouter() <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u043f\u0438\u0448\u0435\u043c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432\u0435\u0431-\u0445\u0443\u043a\u0430:<\/p>\n<pre><code class=\"python\">@router.post(\"\/webhook\") async def webhook(request: Request, session: AsyncSession = Depends(db.get_db_with_commit)):     data = await request.json()     client = http_client_manager.get_client()      if \"message\" in data and \"text\" in data[\"message\"]:         if data[\"message\"][\"text\"] == \"\/start\":             await cmd_start(client=client,                              session=session,                              user_info=data[\"message\"][\"from\"])      elif \"callback_query\" in data:         callback_query = data[\"callback_query\"]         callback_query_id = callback_query[\"id\"]         chat_id = callback_query[\"message\"][\"chat\"][\"id\"]         callback_data: str = callback_query[\"data\"]          if callback_data.startswith('my_booking_'):             await handler_my_appointments_all(client=client,                                               callback_query_id=callback_query_id,                                               chat_id=chat_id,                                               session=session,                                               user_db_id=int(callback_data.replace('my_booking_', '')))         else:             if callback_data == \"booking\":                 await handler_my_appointments(client=client,                                               callback_query_id=callback_query_id,                                               chat_id=chat_id,                                               session=session)             elif callback_data == \"about_us\":                 await handler_about_us(client=client,                                        callback_query_id=callback_query_id,                                        chat_id=chat_id)             elif callback_data == \"home\":                 await handler_back_home(client=client,                                         callback_query_id=callback_query_id,                                         chat_id=chat_id)      return {\"ok\": True} <\/code><\/pre>\n<p>\u042d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 FastAPI \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 POST \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>\/webhook<\/code>. \u0421\u0442\u0440\u043e\u043a\u0430 <code>data = await request.json()<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Telegram \u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u0432 \u043d\u0430\u0448\u0435\u043c \u0431\u043e\u0442\u0435. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u043c \u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u043e\u043c.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 HTTPX:<\/p>\n<pre><code class=\"python\">client = http_client_manager.get_client() <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0438\u0434\u0435\u0442 \u043e\u0442\u0432\u0435\u0442 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0438\u043f\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0442 Telegram. \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u043c <code>{\"ok\": True}<\/code>, \u0447\u0442\u043e\u0431\u044b Telegram \u043f\u043e\u043d\u044f\u043b \u0447\u0442\u043e \u0432\u0441\u0435 \u043f\u0440\u043e\u0448\u043b\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e.<\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0447\u0435\u0440\u0435\u0437 APSCheduler<\/h3>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0433\u043b\u0430\u0432\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c APSCheduler. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0444\u0430\u0439\u043b\u043e\u043c <code>tg_bot\/scheduler_task.py<\/code>.<\/p>\n<h4>\u0418\u043c\u043f\u043e\u0440\u0442\u044b<\/h4>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u0432:<\/p>\n<pre><code class=\"python\">from loguru import logger from app.async_client import http_client_manager from app.config import scheduler from app.tg_bot.methods import bot_send_message, format_appointment from datetime import datetime <\/code><\/pre>\n<h4>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/h4>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e:<\/p>\n<pre><code class=\"python\">async def send_user_noti(user_tg_id: int, appointment: dict):     client = http_client_manager.get_client()     text = format_appointment(appointment, start_text=\"\u2757 \u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u044c \u043a \u0434\u043e\u043a\u0442\u043e\u0440\u0443 \u2757\")     try:         await bot_send_message(client=client, chat_id=user_tg_id, text=text)     except Exception as e:         logger.error(e) <\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430. \u041d\u0430 \u0432\u0445\u043e\u0434 \u043e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 Telegram ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u0435\u0433\u043e \u0437\u0430\u044f\u0432\u043a\u0435, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0435\u043c\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435.<\/p>\n<h4>\u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0432 \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0448\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043b\u0430, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<pre><code class=\"python\">async def schedule_appointment_notification(user_tg_id: int, appointment: dict, notification_time: datetime,                                             reminder_label: str):     \"\"\"     \u041f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c job_id \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f.      :param user_tg_id: ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f Telegram     :param appointment: \u0414\u0430\u043d\u043d\u044b\u0435 \u043e \u0437\u0430\u043f\u0438\u0441\u0438     :param notification_time: \u0412\u0440\u0435\u043c\u044f \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f     :param reminder_label: \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, 'immediate', '24h', '6h', '30min')     \"\"\"     # \u0423\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0434\u0430\u043d\u0438\u044f     job_id = f\"notification_{user_tg_id}_{appointment['id']}_{reminder_label}\"      # \u041f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c \u0437\u0430\u0434\u0430\u043d\u0438\u0435     scheduler.add_job(         send_user_noti,         'date',         run_date=notification_time,         args=[user_tg_id, appointment],         id=job_id,         replace_existing=True     ) <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u0442\u0435, \u0434\u043b\u044f \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043c\u0435\u0442\u043e\u0434 APSCheduler \u2013 <code>add_job<\/code>.<\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p><strong>\u0424\u0443\u043d\u043a\u0446\u0438\u044e<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u0438\u043f \u0437\u0430\u043f\u0443\u0441\u043a\u0430<\/strong> (\u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u00abdate\u00bb).<\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u0440\u0435\u043c\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438<\/strong>.<\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b<\/strong>.<\/p>\n<\/li>\n<li>\n<p><strong>ID \u0437\u0430\u0434\u0430\u0447\u0438<\/strong>.<\/p>\n<\/li>\n<li>\n<p><strong>\u0424\u043b\u0430\u0433<\/strong>, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u0430 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044c \u0437\u0430\u0434\u0430\u0447 \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438 ID. \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043e\u043a \u043f\u0440\u0438 \u043d\u0430\u043a\u043b\u0430\u0434\u043a\u0430\u0445 \u043f\u043e ID.<\/p>\n<\/li>\n<\/ul>\n<h4>\u041e\u0431\u0449\u0430\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044f<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u0441 \u043e\u0431\u0449\u0435\u0439 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0435\u0439. \u0412 \u0447\u0435\u043c \u0441\u0443\u0442\u044c?<\/p>\n<p>\u041f\u0440\u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0434\u043e\u043a\u0442\u043e\u0440\u0443 \u043d\u0430\u0448 \u0434\u0440\u0443\u0433\u043e\u0439 API \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0441\u043a\u043e\u0440\u043e \u043e\u043f\u0438\u0448\u0435\u043c, \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u0438 \u0441\u0440\u0430\u0437\u0443 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u043a \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044e. \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 ID \u0437\u0430\u0434\u0430\u0447\u0438. \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0430\u043d \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0437\u0430\u0434\u0430\u0447 APSCheduler.<\/p>\n<p>\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e, \u0447\u0442\u043e \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043a\u0430\u043a SQLite \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0430\u043c\u0430 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 APSCheduler \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f APSCheduler \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043e \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0445 \u0441 \u0432\u0440\u0430\u0447\u0430\u043c\u0438.<\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043a \u0434\u043e\u043a\u0442\u043e\u0440\u0430\u043c<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u0444\u0430\u0439\u043b\u0443 <code>api\/router.py<\/code> \u0438 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0443. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0435\u0433\u043e:<\/p>\n<pre><code class=\"python\">@router.post(\"\/book\") async def book_appointment_and_schedule_notifications(         booking_request: BookingRequest, session: AsyncSession = Depends(db.get_db_with_commit) ):     \"\"\"     \u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \u0434\u043b\u044f \u0431\u0440\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.     \"\"\"     try:         # \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 user_id \u043f\u043e Telegram ID         user_id = await UserDAO.get_user_id(session=session, telegram_id=booking_request.user_id)          # \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043d\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445         appointment = await BookingDAO.book_appointment(             session=session,             doctor_id=booking_request.doctor_id,             user_id=user_id,             day_booking=booking_request.day_booking,             time_booking=booking_request.time_booking         )         doctor_info = await DoctorDAO.find_one_or_none_by_id(session=session, data_id=booking_request.doctor_id)          # \u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 appointment \u0434\u043b\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439         appointment_details = {             'id': appointment.id,             'day_booking': appointment.day_booking.strftime(\"%Y-%m-%d\"),             'time_booking': appointment.time_booking.strftime(\"%H:%M\"),             'special': doctor_info.special,             'doctor_full_name': f'{doctor_info.first_name} {doctor_info.last_name} {doctor_info.patronymic}'         }          # \u0420\u0430\u0441\u0447\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439         booking_time_str = f\"{appointment_details['day_booking']} {appointment_details['time_booking']}\"         booking_time = datetime.strptime(booking_time_str, \"%Y-%m-%d %H:%M\").replace(tzinfo=MOSCOW_TZ)         now = datetime.now(MOSCOW_TZ)         notification_times = []          # \u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 1: \u0421\u0440\u0430\u0437\u0443         await schedule_appointment_notification(             user_tg_id=booking_request.user_id,             appointment=appointment_details,             notification_time=now,             reminder_label=\"immediate\"         )         notification_times.append(now)          # \u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 2: \u0417\u0430 \u0441\u0443\u0442\u043a\u0438         time_24h = booking_time - timedelta(hours=24)         if time_24h &amp;gt; now:             await schedule_appointment_notification(                 user_tg_id=booking_request.user_id,                 appointment=appointment_details,                 notification_time=time_24h,                 reminder_label=\"24h\"             )             notification_times.append(time_24h)          # \u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 3: \u0417\u0430 6 \u0447\u0430\u0441\u043e\u0432         time_6h = booking_time - timedelta(hours=6)         if time_6h &amp;gt; now:             await schedule_appointment_notification(                 user_tg_id=booking_request.user_id,                 appointment=appointment_details,                 notification_time=time_6h,                 reminder_label=\"6h\"             )             notification_times.append(time_6h)          # \u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 4: \u0417\u0430 30 \u043c\u0438\u043d\u0443\u0442         time_30min = booking_time - timedelta(minutes=30)         if time_30min &amp;gt; now:             await schedule_appointment_notification(                 user_tg_id=booking_request.user_id,                 appointment=appointment_details,                 notification_time=time_30min,                 reminder_label=\"30min\"             )             notification_times.append(time_30min)          # \u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430         notification_times_formatted = [time.strftime(\"%Y-%m-%d %H:%M:%S\") for time in notification_times]          return {             \"status\": \"SUCCESS\",             \"message\": \"\u0417\u0430\u043f\u0438\u0441\u044c \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0438 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u044b!\",             \"appointment\": appointment_details,             \"notification_times\": notification_times_formatted         }      except HTTPException as e:         raise e     except Exception as e:         logger.error(f\"Error in book_appointment_and_schedule_notifications endpoint: {str(e)}\")         raise HTTPException(             status_code=500,             detail=\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0431\u0440\u043e\u043d\u0438 \u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439\"         ) <\/code><\/pre>\n<h3>\u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0432 \u043a\u043e\u0434\u0435, \u0442\u043e \u0443 \u0432\u0430\u0441 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e \u043b\u043e\u0433\u0438\u043a\u0435 \u044d\u0442\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430. \u0412\u043a\u0440\u0430\u0442\u0446\u0435, \u043c\u044b \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0430\u043f\u044b:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u0435\u0433\u043e Telegram ID.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u043b\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u043e\u043a\u0442\u043e\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439. \u041f\u043e \u043a\u0430\u0436\u0434\u043e\u0439 \u0437\u0430\u044f\u0432\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0434\u043d\u043e \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u0447\u0435\u0442\u044b\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0442\u0432\u0435\u0442, \u0435\u0441\u043b\u0438 \u0432\u0441\u0435 \u043f\u0440\u043e\u0448\u043b\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e.<\/p>\n<\/li>\n<\/ol>\n<h3>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e<\/h3>\n<p>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u043e, \u043a\u0430\u043a \u043c\u044b \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e. \u0421\u0443\u0442\u044c \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0438 \u00ab\u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c\u00bb \u043e\u0431 \u044d\u0442\u043e\u043c, \u0442\u0430\u043a \u043a\u0430\u043a FastAPI \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043e \u0437\u0430\u0434\u0430\u0447\u0430\u0445 \u2014 \u043e\u043d \u0438\u0445 \u0443\u0436\u0435 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043b. \u0414\u0430\u043b\u0435\u0435 APScheduler \u0437\u0430\u0439\u043c\u0435\u0442\u0441\u044f \u0438\u0445 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0437\u0430\u043a\u0440\u044b\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0431\u044d\u043a\u0435\u043d\u0434\u0430, \u0438 \u0434\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430\u0448\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u043e \u0447\u0435\u043c \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0443\u0436\u0435 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0433\u043b\u0430\u0432\u0435.<\/p>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0441 Telegram-\u0431\u043e\u0442\u043e\u043c<\/h3>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0433\u043b\u0430\u0432\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0431\u044d\u043a\u0435\u043d\u0434 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram-\u0431\u043e\u0442\u043e\u043c. \u041d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b Telegram \u043d\u0430\u0447\u0430\u043b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e\u0431 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0432 \u043d\u0430\u0448\u0435\u043c \u0431\u043e\u0442\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u0442\u0430\u0442\u044c \u00ab\u0432\u0438\u0434\u0438\u043c\u044b\u043c\u0438\u00bb \u0438 \u00ab\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c\u0438\u00bb.<\/p>\n<h4>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a \u0440\u0430\u0431\u043e\u0442\u0435<\/h4>\n<p>\u0427\u0442\u043e\u0431\u044b Telegram \u043c\u043e\u0433 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 (\u043d\u0430\u0448\u0435 FastAPI \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435), \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e. \u041d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0443\u043d\u043d\u0435\u043b\u044c \u043d\u0430 \u0441\u0432\u043e\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435, \u0430 \u043f\u043e\u0441\u043b\u0435 \u0434\u0435\u043f\u043b\u043e\u044f \u2014 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\">Amvera Cloud<\/a> \u0438\u043b\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b \u043a\u0443\u043f\u0438\u0442\u0435 \u0443 \u043b\u044e\u0431\u043e\u0433\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430.<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0442\u0443\u043d\u043d\u0435\u043b\u044c (\u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f) \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u043b HTTPS-\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u0442\u0430\u043a \u043a\u0430\u043a Telegram \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f\u043c \u0431\u0435\u0437 \u043d\u0435\u0433\u043e \u0438 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u0442\u0443\u043d\u043d\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b, \u043a\u0430\u043a NGROK, TUNA \u0438\u043b\u0438 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435.<\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0434\u0443 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 NGROK.<\/p>\n<h4>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 NGROK<\/h4>\n<ol>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043d\u0430 <a href=\"https:\/\/ngrok.com\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0430\u0439\u0442 NGROK<\/a>.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435\u0441\u044c \u0438 \u0432\u043e\u0439\u0434\u0438\u0442\u0435 \u0432 \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0432\u0430\u0448\u0443 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Windows).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043a\u0430\u0447\u0430\u0439\u0442\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u2014 \u043e\u043d\u0430 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 NGROK \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\">ngrok http 8000<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c <code>8000<\/code> \u2014 \u043f\u043e\u0440\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u0430\u0448 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043e\u0440\u0442.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 NGROK \u0432\u044b\u0434\u0430\u0441\u0442 \u0441\u0441\u044b\u043b\u043a\u0443 \u0432\u0438\u0434\u0430 <code>https:\/\/&amp;lt;\u0432\u0430\u0448-\u0434\u043e\u043c\u0435\u043d&amp;gt;.ngrok.io<\/code>. \u041d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0435\u0451 \u043a\u0430\u043a \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0443\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>.env<\/code> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0434\u043b\u044f <code>BASE_SITE<\/code>.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u0430\u0439\u043b\u0430 app\/main.py<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0444\u0430\u0439\u043b\u0430 <code>app\/main.py<\/code>. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u0432:<\/p>\n<pre><code class=\"python\">import json from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from loguru import logger from fastapi.staticfiles import StaticFiles from app.api.router import router as router_api from app.async_client import http_client_manager from app.config import settings, scheduler from app.tg_bot.router import router as router_tg_bot <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0432\u0435\u0431\u0445\u0443\u043a \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 Telegram:<\/p>\n<pre><code class=\"python\">async def set_webhook(client):     \"\"\"\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0432\u0435\u0431\u0445\u0443\u043a \u0434\u043b\u044f Telegram-\u0431\u043e\u0442\u0430.\"\"\"     try:         response = await client.post(f\"{settings.get_tg_api_url()}\/setWebhook\", json={             \"url\": settings.get_webhook_url()         })         response_data = response.json()         if response.status_code == 200 and response_data.get(\"ok\"):             logger.info(f\"Webhook \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d: {response_data}\")         else:             logger.error(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0432\u0435\u0431\u0445\u0443\u043a\u0430: {response_data}\")     except Exception as e:         logger.exception(f\"\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0435\u0431\u0445\u0443\u043a: {e}\") <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Telegram \u0443\u0437\u043d\u0430\u044e\u0442, \u0447\u0442\u043e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442. \u0415\u0441\u043b\u0438 \u043e\u0442\u0432\u0435\u0442 \u00abok\u00bb, \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0445\u0443\u043a \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d, \u0438 Telegram \u0437\u043d\u0430\u0435\u0442, \u043a\u0443\u0434\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0431\u043e\u0442\u0430:<\/p>\n<pre><code class=\"python\">async def send_admin_msg(client, text):     for admin in settings.ADMIN_IDS:         try:             await client.post(f\"{settings.get_tg_api_url()}\/sendMessage\",                               json={\"chat_id\": admin, \"text\": text, \"parse_mode\": \"HTML\"})         except Exception as E:             logger.exception(f\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0430\u0434\u043c\u0438\u043d\u0443: {E}\") <\/code><\/pre>\n<h4>\u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f FastAPI<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b FastAPI, \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\n<p>\u0418\u043d\u0438\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u043a\u043b\u0438\u0435\u043d\u0442 HTTPX.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f scheduler.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043b\u0441\u044f \u0432\u0435\u0431\u0445\u0443\u043a.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u043e\u0441\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0435 \u043c\u0435\u043d\u044e \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>\/start<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0431\u043e\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b:<\/p>\n<ol>\n<li>\n<p>\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0431\u043e\u0442 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p>\u041c\u044b \u0440\u0430\u0437\u0440\u044b\u0432\u0430\u043b\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 HTTPX.<\/p>\n<\/li>\n<li>\n<p>\u041c\u044b \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u043b\u0438 scheduler.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u043e\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f:<\/p>\n<pre><code class=\"python\">@asynccontextmanager async def lifespan(app: FastAPI):     \"\"\"\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u043e\u0442\u0430.\"\"\"     client = http_client_manager.get_client()     logger.info(\"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u043e\u0442\u0430...\")     scheduler.start()     await set_webhook(client)     await client.post(f\"{settings.get_tg_api_url()}\/setMyCommands\",                       data={\"commands\": json.dumps([{\"command\": \"start\", \"description\": \"\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u043c\u0435\u043d\u044e\"}])})     await send_admin_msg(client, \"\u0411\u043e\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d!\")     yield     logger.info(\"\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u043e\u0442\u0430...\")     await send_admin_msg(client, \"\u0411\u043e\u0442 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d!\")     await http_client_manager.close_client()     scheduler.shutdown() <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 FastAPI, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0432 \u043a \u043d\u0435\u043c\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430:<\/p>\n<pre><code class=\"python\">app = FastAPI(lifespan=lifespan)<\/code><\/pre>\n<h4>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432<\/h4>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<pre><code class=\"python\">app.mount('\/static', StaticFiles(directory='app\/static'), name='static')<\/code><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0434\u043e\u043a\u0442\u043e\u0440\u043e\u0432 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0431\u044d\u043a\u0435\u043d\u0434\u0430, \u0430 \u043d\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430. \u0414\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 <code>static<\/code> \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 <code>app<\/code>, \u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0451 \u2014 \u043f\u0430\u043f\u043a\u0443 <code>images<\/code>, \u043a\u0443\u0434\u0430 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u0435 \u0444\u043e\u0442\u043e \u0432\u0441\u0435\u0445 \u0434\u043e\u043a\u0442\u043e\u0440\u043e\u0432. \u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0444\u043e\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>\/static\/images\/photo.jpg<\/code>.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 CORS<\/h4>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c Middleware \u0434\u043b\u044f CORS:<\/p>\n<pre><code class=\"python\">app.add_middleware(     CORSMiddleware,     allow_origins=[\"*\"],  # \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0432\u0441\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438     allow_credentials=True,     allow_methods=[\"*\"],  # \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b     allow_headers=[\"*\"],  # \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u043c \u0432\u0441\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 ) <\/code><\/pre>\n<h4>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u0432<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u0443\u0442\u0435\u0440\u044b Telegram-\u0431\u043e\u0442\u0430 \u0438 API:<\/p>\n<pre><code class=\"python\">app.include_router(router_api) app.include_router(router_tg_bot) <\/code><\/pre>\n<h4>\u0417\u0430\u043f\u0443\u0441\u043a \u0431\u043e\u0442\u0430<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0431\u043e\u0442\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<pre><code class=\"bash\">uvicorn app.main:app --reload --port 8000 <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0440\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u043f\u043e\u0440\u0442\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0443\u043d\u043d\u0435\u043b\u044f \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c FastApi \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b \u043a\u043b\u0438\u043a\u043d\u0443\u043b\u0438 \u043d\u0430 \/start \u0432 \u0431\u043e\u0442\u0435 \u0438 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c \u0430\u0439\u0434\u0438 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 <code>ADMIN_IDS<\/code> \u0444\u0430\u0439\u043b\u0430 <code>.env<\/code>.<\/p>\n<p>\u0418\u043d\u0430\u0447\u0435 \u0431\u043e\u0442 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432\u0430\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435.<\/p>\n<h3>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0434 \u0434\u0435\u043f\u043b\u043e\u0435\u043c<\/h3>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u044d\u0442\u0430\u043f\u0443 \u0434\u0435\u043f\u043b\u043e\u044f, \u0432\u0430\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0433\u043e API \u0438 Telegram-\u0431\u043e\u0442\u0430. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434-\u0447\u0430\u0441\u0442\u044c \u0435\u0449\u0435 \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430, \u0432\u0441\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e.<\/p>\n<h4>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 API<\/h4>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u0432 API \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 \u0432\u0430\u0448\u0435\u0433\u043e FastAPI \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>\/docs<\/code>. <\/p>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0432\u0441\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u0430 \u0438 \u0435\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/682\/dc7\/7b5\/682dc77b5012b58a752438d6e5c2138b.png\" alt=\"\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0441 API-\u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438\" title=\"\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0441 API-\u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438\" width=\"1815\" height=\"431\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/682\/dc7\/7b5\/682dc77b5012b58a752438d6e5c2138b.png\"\/><\/p>\n<div><figcaption>\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0441 API-\u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438<\/figcaption><\/div>\n<\/figure>\n<h4>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Telegram-\u0431\u043e\u0442\u0430<\/h4>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f Telegram-\u0431\u043e\u0442\u0430, \u0442\u043e \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<ul>\n<li>\n<p><strong>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/strong>: \u041f\u043e\u0441\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>\/start<\/code> \u0431\u043e\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/228\/4ce\/ae2\/2284ceae2555cf227d7248a2800ae1fc.png\" width=\"700\" height=\"537\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/228\/4ce\/ae2\/2284ceae2555cf227d7248a2800ae1fc.png\"\/><\/figure>\n<ul>\n<li>\n<p><strong>\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435<\/strong>: \u0411\u043e\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0438\u043d\u043b\u0430\u0439\u043d-\u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u043b\u0438 \u043b\u0435\u0433\u043a\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043d\u0438\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u041e \u043d\u0430\u0441\u00bb<\/strong>: \u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041e \u043d\u0430\u0441\u00bb \u0431\u043e\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u043e \u043a\u043b\u0438\u043d\u0438\u043a\u0435, \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043e \u0435\u0435 \u0443\u0441\u043b\u0443\u0433\u0430\u0445 \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u0445.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/89b\/639\/71e\/89b63971e59f8873d3c09aa4e56d97da.png\" width=\"706\" height=\"805\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/89b\/639\/71e\/89b63971e59f8873d3c09aa4e56d97da.png\"\/><\/figure>\n<ul>\n<li>\n<p>\u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u041c\u043e\u0438 \u0437\u0430\u043f\u0438\u0441\u0438\u00bb: \u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u044d\u0442\u0443 \u043a\u043d\u043e\u043f\u043a\u0443 \u0431\u043e\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0432\u0435\u0434\u043e\u043c\u0438\u0442\u044c \u0432\u0430\u0441 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043f\u043e\u043a\u0430 \u043d\u0435\u0442. \u042d\u0442\u043e \u0432\u043f\u043e\u043b\u043d\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u044d\u0442\u0430\u043f\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f. \u0412 \u043c\u043e\u0451\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043a \u0432\u0440\u0430\u0447\u0430\u043c, \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u043f\u0440\u0438\u043d\u044f\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/781\/55d\/465\/78155d46512b263d23409b94209c0429.png\" width=\"739\" height=\"346\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/781\/55d\/465\/78155d46512b263d23409b94209c0429.png\"\/><\/figure>\n<p>\u0422\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u044d\u0442\u0430\u043f\u0443 \u0434\u0435\u043f\u043b\u043e\u044f.<\/p>\n<h3>\u0414\u0435\u043f\u043b\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 Amvera Cloud<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0443 \u043d\u0430\u0448\u0435\u0433\u043e FastApi \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\"><strong>Amvera Cloud<\/strong><\/a>.<\/p>\n<p><strong>\u0428\u0430\u0433 1: \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 FastAPI \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/strong><\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c FastAPI \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435.<\/p>\n<p><strong>\u0428\u0430\u0433 2: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430<\/strong><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 Amvera. \u041d\u0430\u0437\u043e\u0432\u0438\u0442\u0435 \u0435\u0433\u043e <code>amvera.yml<\/code> \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"yaml\">meta:   environment: python   toolchain:     name: pip     version: 3.12 build:   requirementsPath: requirements.txt run:   persistenceMount: \/data   containerPort: 8000   command: uvicorn app.main:app --host 0.0.0.0 --port 8000 <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441\u0443 Amvera, \u043a\u0430\u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>\u041e\u0441\u043e\u0431\u043e\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443: <code>persistenceMount: \/data<\/code>. \u041f\u043e\u0441\u043b\u0435 \u0434\u0435\u043f\u043b\u043e\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0447\u0442\u043e\u0431 \u0444\u0430\u0439\u043b\u044b \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u0445\u043e\u0434\u0438\u043b\u0438\u0441\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u043f\u0430\u043f\u043a\u0435 \/data, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0430\u0436\u043d\u043e \u043f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f.<\/p>\n<p><strong>\u0428\u0430\u0433 3: \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0434\u0435\u043f\u043b\u043e\u044f<\/strong><\/p>\n<p>\u0421\u0430\u043c \u0434\u0435\u043f\u043b\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\">Amvera Cloud.<\/a><\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0444\u0430\u0439\u043b\u044b FastAPI \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u043b\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434 GIT).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0432\u044f\u0436\u0438\u0442\u0435 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f HTTPS (\u044d\u0442\u043e \u043e\u0434\u043d\u0430 \u0438\u0437 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 Amvera).<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 Amvera Cloud, \u0435\u0441\u043b\u0438 \u0432\u044b \u0435\u0449\u0451 \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u044d\u0442\u043e\u0433\u043e. \u041d\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442 111 \u0440\u0443\u0431\u043b\u0435\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0431\u0430\u043b\u0430\u043d\u0441, \u0447\u0442\u043e \u0432\u043f\u043e\u043b\u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.<\/p>\n<h4>\u041f\u043e\u0448\u0430\u0433\u043e\u0432\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f<\/h4>\n<ol>\n<li>\n<p><strong>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/strong><\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 \u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u0430\u0431\u0438\u043d\u0435\u0442. \u041f\u043e\u0441\u043b\u0435 \u043a\u043b\u0438\u043a\u0430\u0435\u043c \u043d\u0430 &#171;\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442&#187;. \u0414\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \u0438\u043c\u044f, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0438\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u043d\u0435 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445) \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 &#171;\u0414\u0430\u043b\u0435\u0435&#187;.<\/p>\n<\/li>\n<\/ul>\n<ol start=\"2\">\n<li>\n<p><strong>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432<\/strong><\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>\n<p>\u041d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u044d\u043a\u0440\u0430\u043d\u0435 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u043f\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 GIT \u0438 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u00ab\u0427\u0435\u0440\u0435\u0437 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u00bb. \u042f \u0432\u044b\u0431\u0440\u0430\u043b \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u043b \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u0436\u043c\u0438\u0442\u0435 &#171;\u0414\u0430\u043b\u0435\u0435&#187;.<\/p>\n<\/li>\n<\/ul>\n<ol start=\"3\">\n<li>\n<p><strong>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a<\/strong><\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>\n<p>\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0441\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0432\u0435\u0434\u0435\u043d\u044b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e; \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0432\u043d\u0435\u0441\u0438\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u043a\u0440\u0430\u043d\u0435 \u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 &#171;\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c&#187;.<\/p>\n<\/li>\n<\/ul>\n<ol start=\"4\">\n<li>\n<p><strong>\u041f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043c\u0435\u043d\u0438<\/strong><\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>\n<p>\u041f\u0440\u0438\u0432\u044f\u0436\u0438\u0442\u0435 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443 (\u0432\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f, \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0435\u0433\u043e \u0437\u0430 \u043f\u0430\u0440\u0443 \u043a\u043b\u0438\u043a\u043e\u0432).<\/p>\n<\/li>\n<\/ul>\n<h4>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043c\u0435\u043d\u0438<\/h4>\n<ol>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 FastAPI.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 \u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u00bb.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0432\u044f\u0436\u0438\u0442\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f, \u043a\u0430\u043a \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435 \u043d\u0438\u0436\u0435.<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/561\/9b3\/013\/5619b3013856a79a479b4352f6da8ab8.png\" width=\"1351\" height=\"708\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/561\/9b3\/013\/5619b3013856a79a479b4352f6da8ab8.png\"\/><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0441 \u0432\u0430\u0448\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043d\u0430 \u0442\u043e\u043c \u0436\u0435 \u044d\u043a\u0440\u0430\u043d\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u043f\u0446\u0438\u044e &#171;\u0421\u0432\u043e\u0439 \u0434\u043e\u043c\u0435\u043d&#187; \u0438 \u0441\u043b\u0435\u0434\u0443\u0439\u0442\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c. \u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e Amvera \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 HTTPS-\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0434\u043b\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043c\u0435\u043d\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0444\u0430\u0439\u043b\u043e\u043c .env. \u041c\u044b \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f. \u0415\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 BASE_SITE. \u0412 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u0430\u043a:<\/p>\n<pre><code>BASE_SITE=https:\/\/vue3fastapi-yakvenalex.amvera.io<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u0441\u044c \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u00ab\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439\u00bb, \u0443\u0434\u0430\u043b\u0438\u0442\u0435 \u0441\u0442\u0430\u0440\u044b\u0439 \u0444\u0430\u0439\u043b <code>.env<\/code> \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>BASE_SITE<\/code>. \u0417\u0430\u0442\u0435\u043c \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041f\u0435\u0440\u0435\u0441\u043e\u0431\u0440\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u00bb (\u0432\u0435\u0440\u0445\u043d\u044f\u044f \u0441\u0442\u0440\u0435\u043b\u043a\u0430 \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435). \u0427\u0435\u0440\u0435\u0437 2-3 \u043c\u0438\u043d\u0443\u0442\u044b \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c\u0441\u044f, \u0438 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0442 \u0431\u043e\u0442\u0430 \u043e \u0435\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d26\/190\/3a7\/d261903a7d87fcdb19e7cf3fc971dd23.png\" alt=\"\" title=\"\" width=\"1325\" height=\"641\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d26\/190\/3a7\/d261903a7d87fcdb19e7cf3fc971dd23.png\"\/><\/figure>\n<p>\u041f\u043e\u0437\u0434\u0440\u0430\u0432\u043b\u044f\u044e! \u0427\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0443 \u043c\u0438\u043d\u0443\u0442 \u0432\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f, \u0438 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430, \u043e \u0447\u0451\u043c \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435.<\/p>\n<p>\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c API \u043f\u043e\u0441\u043b\u0435 \u0434\u0435\u043f\u043b\u043e\u044f!<\/p>\n<p>\u041f\u043e\u043a\u043b\u0430\u0446\u0430\u0442\u044c \u0431\u043e\u0442\u0430 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0442\u0443\u0442: <a href=\"https:\/\/t.me\/Vue3_FastApiBOT\">Vue3 FastApi<\/a>.<\/p>\n<h4>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h4>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u043b\u0438 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0432 \u043c\u043e\u0449\u043d\u044b\u0439 \u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0431\u044d\u043a\u0435\u043d\u0434. \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 API \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0441\u0432\u044f\u0437\u043a\u0438 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 <strong>Vue.js 3<\/strong>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u043d\u043e \u0438 \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434-\u0440\u0435\u0448\u0435\u043d\u0438\u0439. \u042d\u0442\u043e\u0442 API \u043b\u0435\u0433\u043a\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u043b\u044e\u0431\u044b\u043c\u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f\u043c\u0438 \u2014 \u0431\u0443\u0434\u044c \u0442\u043e <strong>React<\/strong>, <strong>Angular<\/strong>, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0434\u0435\u0441\u043a\u0442\u043e\u043f\u043d\u044b\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b.<\/p>\n<p>\u041e\u0441\u043e\u0431\u043e\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0441\u0442\u043e\u0438\u0442 \u0443\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0435\u043c\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Telegram-\u0431\u043e\u0442\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0447\u0438\u0441\u0442\u043e\u0433\u043e <strong>Telegram Bot API<\/strong>. \u041c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u043e\u0442\u043e\u043c \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0432\u0440\u043e\u0434\u0435 <strong>Aiogram 3<\/strong>. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044f \u043f\u043e\u043a\u0430\u0437\u0430\u043b \u0432\u0430\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0441\u0432\u044f\u0437\u043a\u0438 Telegram-\u0431\u043e\u0442\u0430 \u0438 <strong>FastAPI<\/strong>: \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u043e\u0442 \u2014 \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d POST-\u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 Telegram.<\/p>\n<p>\u0415\u0449\u0435 \u043e\u0434\u043d\u0430 \u0432\u0430\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u2014 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <strong>APScheduler<\/strong>. \u041a\u0430\u043a \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0432\u0441\u0435\u0433\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u0438 \u043d\u0430\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u043e\u0449\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 \u0431\u043e\u0442\u0430.<\/p>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\">Amvera Cloud<\/a>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434-\u0447\u0430\u0441\u0442\u0438.<\/p>\n<p>\u041f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u0438\u0437\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u043c. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u0441\u043c\u0435\u043b\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0438\u0445 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u0438\u043b\u0438 \u0432 \u043c\u043e\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435 \u0432 Telegram.<\/p>\n<p>\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e, \u0447\u0442\u043e \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435 <strong>\u00ab<\/strong><a href=\"https:\/\/t.me\/PythonPathMaster\"><strong>\u041b\u0435\u0433\u043a\u0438\u0439 \u043f\u0443\u0442\u044c \u0432 Python<\/strong><\/a><strong>\u00bb<\/strong> \u0432\u044b \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0435\u0434\u0438\u043d\u043e\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u043d\u043e \u0438 \u043f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u043a\u0430\u043a \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434, \u0442\u0430\u043a \u0438 \u0431\u044d\u043a\u0435\u043d\u0434). \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0442\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0441\u043a\u043b\u044e\u0437\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0438\u0433\u0434\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u044b\u043b\u0430 \u0434\u043b\u044f \u0432\u0430\u0441 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0442\u0435 \u0435\u0451 \u043b\u0430\u0439\u043a\u043e\u043c \u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c. \u041e\u0431\u0440\u0430\u0442\u043d\u0430\u044f \u0441\u0432\u044f\u0437\u044c \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b \u0442\u0430\u043a\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0440\u0435\u0430\u043a\u0446\u0438\u0438 \u0441\u0442\u0430\u043d\u0435\u0442 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043d\u0435 \u0432\u043e\u0441\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d, \u0438 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0439.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0451. \u0414\u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0438 \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0433\u0434\u0435 \u043c\u044b \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 API \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <strong>Vue.js 3<\/strong>.<\/p>\n<p>\u041d\u0435 \u043f\u0440\u043e\u0449\u0430\u0435\u043c\u0441\u044f!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><\/p>\n<div class=\"tm-article-poll-container\"><!--[--><\/p>\n<div class=\"tm-article-poll tm-article-poll_variant-bordered\">\n<div class=\"tm-notice tm-notice_positive tm-article-poll__notice\"><!----><\/p>\n<div class=\"tm-notice__inner\"><!----><\/p>\n<div class=\"tm-notice__content\" data-test-id=\"notice-content\"><!--[--><span>\u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u043f\u0440\u043e\u0441\u0435. <a rel=\"nofollow\" href=\"\/kek\/v1\/auth\/habrahabr\/?back=\/ru\/companies\/amvera\/articles\/873108\/&#038;hl=ru\">\u0412\u043e\u0439\u0434\u0438\u0442\u0435<\/a>, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430.<\/span><!--]--><\/div>\n<\/div>\n<\/div>\n<p><!--[--><\/p>\n<div class=\"tm-article-poll__header\">\u0411\u0443\u0434\u0435\u0442\u0435 \u0436\u0434\u0430\u0442\u044c \u0432\u044b\u0445\u043e\u0434\u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438?<\/div>\n<div class=\"tm-article-poll__answers\"><!--[--><\/p>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent tm-article-poll__answer-percent_winning\">80% <\/span><span class=\"tm-article-poll__answer-label\">\u041a\u043e\u043d\u0435\u0447\u043d\u043e!<\/span><span class=\"tm-article-poll__answer-votes\">12<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress tm-article-poll__answer-progress_winning\" style=\"width: 80%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">13.33% <\/span><span class=\"tm-article-poll__answer-label\">\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u2026<\/span><span class=\"tm-article-poll__answer-votes\">2<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 13.33%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">0% <\/span><span class=\"tm-article-poll__answer-label\">\u041d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d<\/span><span class=\"tm-article-poll__answer-votes\">0<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 0%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">0% <\/span><span class=\"tm-article-poll__answer-label\">\u0416\u0434\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u043d\u043e \u043d\u0430\u043f\u0438\u0448\u0438. \u041a\u043e\u043c\u0443-\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e<\/span><span class=\"tm-article-poll__answer-votes\">0<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 0%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">6.67% <\/span><span class=\"tm-article-poll__answer-label\">\u0416\u0434\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u043d\u0435 \u043f\u0438\u0448\u0438, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430!<\/span><span class=\"tm-article-poll__answer-votes\">1<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 6.67%\"><\/div>\n<\/div>\n<\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll__stats\"> \u041f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043b\u0438 15 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.   \u0412\u043e\u0437\u0434\u0435\u0440\u0436\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u043d\u0435\u0442. <\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll tm-article-poll_variant-bordered\">\n<div class=\"tm-notice tm-notice_positive tm-article-poll__notice\"><!----><\/p>\n<div class=\"tm-notice__inner\"><!----><\/p>\n<div class=\"tm-notice__content\" data-test-id=\"notice-content\"><!--[--><span>\u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u043f\u0440\u043e\u0441\u0435. <a rel=\"nofollow\" href=\"\/kek\/v1\/auth\/habrahabr\/?back=\/ru\/companies\/amvera\/articles\/873108\/&#038;hl=ru\">\u0412\u043e\u0439\u0434\u0438\u0442\u0435<\/a>, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430.<\/span><!--]--><\/div>\n<\/div>\n<\/div>\n<p><!--[--><\/p>\n<div class=\"tm-article-poll__header\">\u0423\u0437\u043d\u0430\u043b\u0438 \u043b\u0438 \u0432\u044b \u043d\u043e\u0432\u043e\u0435, \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0432 \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e?<\/div>\n<div class=\"tm-article-poll__answers\"><!--[--><\/p>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent tm-article-poll__answer-percent_winning\">85.71% <\/span><span class=\"tm-article-poll__answer-label\">\u0414\u0430<\/span><span class=\"tm-article-poll__answer-votes\">12<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress tm-article-poll__answer-progress_winning\" style=\"width: 85.71%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">14.29% <\/span><span class=\"tm-article-poll__answer-label\">\u041d\u0435\u0442<\/span><span class=\"tm-article-poll__answer-votes\">2<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 14.29%\"><\/div>\n<\/div>\n<\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll__stats\"> \u041f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043b\u0438 14 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.   \u0412\u043e\u0437\u0434\u0435\u0440\u0436\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u043d\u0435\u0442. <\/div>\n<p><!--]--><\/div>\n<p><!--]--><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/873108\/\"> https:\/\/habr.com\/ru\/articles\/873108\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0440\u0430\u0434 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u0430\u043c \u043d\u043e\u0432\u044b\u0439 \u043a\u0440\u0443\u043f\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u043d\u0435\u0435 \u043d\u0435 \u043e\u0441\u0432\u0435\u0449\u0430\u043b\u0438\u0441\u044c \u0432 \u043c\u043e\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430 \u0441 MiniApp (\u0440\u0430\u043d\u0435\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u043c \u043a\u0430\u043a WebApp) \u2014 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0431\u043e\u0442 \u0441 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043c\u0438\u043d\u0438-\u0441\u0430\u0439\u0442\u043e\u043c \u043f\u0440\u044f\u043c\u043e \u0432 Telegram. \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u0432\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430:<\/p>\n<ul>\n<li>\n<p>FastAPI \u2014 \u043c\u043e\u0449\u043d\u044b\u0439 Python-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u043c \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 API \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0431\u044d\u043a\u0435\u043d\u0434 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0438\u0439, \u043a\u0430\u043a API \u043c\u0435\u0442\u043e\u0434\u044b, \u0442\u0430\u043a \u0438 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c\u043c \u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>Vue.js 3 \u2014 JavaScript-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0437\u0430 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u0438\u0445 \u0434\u0432\u0443\u0445 \u0441\u0442\u043e\u043b\u043f\u043e\u0432, \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438\u0437 \u043c\u0438\u0440\u0430 Python \u0438 JavaScript, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043c \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u0441 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041e \u043d\u0438\u0445 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0447\u043d\u0435\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0441\u0442\u0435\u043a \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439.<\/p>\n<h3>\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c?<\/h3>\n<p>\u041d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u2014 \u044d\u0442\u043e \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442 \u0434\u043b\u044f \u0432\u044b\u0434\u0443\u043c\u0430\u043d\u043d\u043e\u0439 \u043a\u043b\u0438\u043d\u0438\u043a\u0438 \u00ab\u0417\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u041f\u043b\u044e\u0441\u00bb. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043a \u0432\u0440\u0430\u0447\u0443 \u0432 \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0434\u0435\u043d\u044c \u0438 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p>\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u2014 \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0437\u0430\u043f\u0438\u0441\u0438 \u043a \u0432\u0440\u0430\u0447\u0443. \u042f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u044d\u0442\u043e\u0442 \u0431\u043b\u043e\u043a \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0442\u043e\u0433\u0434\u0430 \u043a\u0430\u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u0442\u0440\u0435\u0445 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>API \u2014 \u0441\u0435\u0440\u0434\u0446\u0435\u0432\u0438\u043d\u0430 \u043b\u043e\u0433\u0438\u043a\u0438, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u0444\u0430\u0439\u043b\u044b \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442 \u2014 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u0435\u0437 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 Telegram API \u043d\u0430 \u0431\u0430\u0437\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 HTTPX, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0439 \u0441 FastApi.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u2014 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b:<\/p>\n<ul>\n<li>\n<p>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0432\u044b\u0431\u043e\u0440\u0430 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f (\u0442\u0435\u0440\u0430\u043f\u0438\u044f, \u0441\u0442\u043e\u043c\u0430\u0442\u043e\u043b\u043e\u0433\u0438\u044f \u0438 \u0442. \u0434.) \u0441 \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u043e\u0438\u0441\u043a\u043e\u043c. \u041e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0432\u0438\u0434\u0435 \u043a\u0430\u0440\u0442\u043e\u0447\u0435\u043a, \u043a\u0430\u043a \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0440\u0430\u0447\u0430 \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430 \u043f\u0440\u0438\u0435\u043c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u043b\u043e\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b \u00ab\u041e \u043d\u0430\u0441\u00bb.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0438 \u0447\u0435\u0440\u0435\u0437 MiniApp.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432\u0441\u0435\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 \u043d\u0430\u043f\u0438\u0448\u0435\u043c API, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0447\u0438\u0441\u0442\u044b\u0439 Telegram Bot API \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 HTTPX.<\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/67849fd95d5079d77e30a356\" data-style=\"\" id=\"67849fd95d5079d77e30a356\" width=\"\"><\/div>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0431\u044d\u043a\u0435\u043d\u0434\u0430: API-\u043c\u0435\u0442\u043e\u0434\u044b, Telegram \u0431\u043e\u0442 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 (\u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e). \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0447\u0430\u0441\u0442\u0438 \u043d\u0430 VUE.JS 3.<\/p>\n<h3>\u0422\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0442\u0435\u043a<\/h3>\n<p><strong>\u0421\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430<\/strong>:<\/p>\n<ul>\n<li>\n<p>Tailwind CSS \u2014 \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0442\u0438\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0431\u0435\u0437 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f CSS \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<\/li>\n<li>\n<p>FontAwesome \u2014 \u0434\u043b\u044f \u0438\u043a\u043e\u043d\u043e\u043a.<\/p>\n<\/li>\n<\/ul>\n<p><strong>Python<\/strong>:<\/p>\n<ul>\n<li>\n<p>FastAPI \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 API.<\/p>\n<\/li>\n<li>\n<p>SQLAlchemy 2 \u2014 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f SQLite).<\/p>\n<\/li>\n<li>\n<p>Apscheduler \u2014 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439).<\/p>\n<\/li>\n<li>\n<p>HTTPX \u2014 \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 Telegram API.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e: Loguru, Pydantic 2, Uvicorn \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<p><strong>JavaScript<\/strong>:<\/p>\n<ul>\n<li>\n<p>Vue.js 3 \u2014 \u043e\u0441\u043d\u043e\u0432\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430.<\/p>\n<\/li>\n<li>\n<p>VueRouter \u2014 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u043d\u043e\u0433\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>useFetch \u2014 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API.<\/p>\n<\/li>\n<li>\n<p>VueTG \u2014 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e MiniApp.<\/p>\n<\/li>\n<\/ul>\n<h3>\u042d\u0442\u0430\u043f\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h3>\n<ol>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 SQLAlchemy, Aiosqlite \u0438 Alembic.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 API \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043e\u0442\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c HTTPX.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 (APSCHEDULER).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u043d\u0430 Vue.js 3.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0435\u043f\u043b\u043e\u0439.<\/p>\n<\/li>\n<\/ol>\n<h3>\u0414\u0435\u043f\u043b\u043e\u0439<\/h3>\n<p>\u0425\u043e\u0447\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0434\u0435\u043f\u043b\u043e\u044f. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u044e \u0432\u0430\u043c \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u0435\u043f\u043b\u043e\u0439 \u0434\u0432\u0430\u0436\u0434\u044b: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0431\u044d\u043a\u0435\u043d\u0434-\u0447\u0430\u0441\u0442\u044c, \u0430 \u0437\u0430\u0442\u0435\u043c \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434.<\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441 <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\">Amvera Cloud<\/a>. \u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u044f \u0432\u044b\u0431\u0438\u0440\u0430\u044e \u0437\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0443 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c. \u0422\u043e \u0435\u0441\u0442\u044c, \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u043a\u043e\u0434\u0438\u043d\u0433\u0435, \u0442\u043e \u0432\u044b \u0442\u043e\u0447\u043d\u043e \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f. \u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438, \u0434\u0435\u043f\u043b\u043e\u0439 \u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u0434\u043d\u0430 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0448\u0430\u0433\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430 \u0441 HTTPS.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0431\u043e\u0440\u043a\u0430.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a \u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u0430\u043a \u043e\u043f\u0438\u0441\u0430\u043b \u0432\u044b\u0448\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0441\u0442\u0430\u0442\u044c\u044e \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0430\u043c \u044d\u0442\u043e\u0442 \u0431\u043b\u043e\u043a \u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e.<\/p>\n<h4>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440<\/h4>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u043c\u0441\u044f \u0432 \u043a\u043e\u0434, \u0445\u043e\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043b \u0443\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u0435\u0441\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0432 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u0435\u0433\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043d\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u044b \u0447\u0438\u0442\u0430\u0435\u0442\u0435 <strong>\u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u044c<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0431\u044d\u043a\u0435\u043d\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0410 \u0438\u043c\u0435\u043d\u043d\u043e:<\/p>\n<ul>\n<li>\n<p><strong>API-\u043c\u0435\u0442\u043e\u0434\u044b<\/strong>,<\/p>\n<\/li>\n<li>\n<p><strong>Telegram-\u0431\u043e\u0442<\/strong>,<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u043e\u0433\u0438\u043a\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/strong>.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u043d\u0430 Vue.JS 3, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u044d\u0442\u0438\u043c API.<\/p>\n<p>\u042f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c \u0432\u0441\u0451 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u0432\u0430\u0441 \u0441\u043c\u043e\u0433 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f. \u041d\u043e \u043d\u0443\u0436\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0438 \u043f\u043e\u0434\u0445\u043e\u0434\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u0432 \u043c\u043d\u043e\u0433\u043e\u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043c\u0430\u0440\u0430\u0444\u043e\u043d, \u044f \u0431\u0443\u0434\u0443 \u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u0438\u0437\u043b\u0438\u0448\u043d\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u0435\u0439. \u0415\u0441\u043b\u0438 \u0432\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0438\u0437 \u044d\u0442\u0438\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043c\u043e\u0438\u043c\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c\u0438 \u0441\u0442\u0430\u0442\u044c\u044f\u043c\u0438, \u0433\u0434\u0435 \u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b <strong>FastAPI<\/strong> \u0438 <strong>SQLAlchemy<\/strong>. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b.<\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f <strong>Vue.js 3<\/strong>, \u0440\u0430\u043d\u0435\u0435 \u044f \u043e \u043d\u0451\u043c \u043d\u0435 \u043f\u0438\u0441\u0430\u043b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435, \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u044b \u044d\u0442\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u0430\u043c \u043b\u0435\u0433\u0447\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u043d\u0443\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0433\u043b\u044f\u043d\u0438\u0442\u0435 \u0432 \u043c\u043e\u0451 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e <strong>\u00ab<\/strong><a href=\"https:\/\/t.me\/PythonPathMaster\"><strong>\u041b\u0451\u0433\u043a\u0438\u0439 \u043f\u0443\u0442\u044c \u0432 Python<\/strong><\/a><strong>\u00bb<\/strong>. \u041d\u0430\u0441 \u0443\u0436\u0435 \u0431\u043e\u043b\u0435\u0435 2000 \u0435\u0434\u0438\u043d\u043e\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0434\u0440\u0443\u0433 \u0434\u0440\u0443\u0433\u0430. \u0422\u0430\u043c \u0432\u044b \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u044d\u043a\u0441\u043a\u043b\u044e\u0437\u0438\u0432\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u0432\u043e\u0451\u043c Telegram-\u043a\u0430\u043d\u0430\u043b\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0434\u0430\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043c\u043d\u0435 \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430.<\/p>\n<p>\u041a\u0441\u0442\u0430\u0442\u0438, \u043f\u043e\u043b\u043d\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u0443\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0442\u0435 \u0435\u0451 \u043b\u0430\u0439\u043a\u043e\u043c \u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c. \u0414\u043b\u044f \u043c\u0435\u043d\u044f \u044d\u0442\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0442\u0438\u0432\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c, \u043d\u043e \u0438 \u043b\u0443\u0447\u0448\u0438\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u044f \u043d\u0430 \u0432\u0435\u0440\u043d\u043e\u043c \u043f\u0443\u0442\u0438.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c!<\/p>\n<h3>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0431\u044d\u043a\u0435\u043d\u0434\u0430<\/h3>\n<p><strong>\u0428\u0430\u0433 1: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/strong><\/p>\n<p>\u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u2014 \u044d\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043b\u044e\u0431\u0438\u043c\u043e\u0435 IDE, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u044b \u043f\u0440\u0438\u0432\u044b\u043a\u043b\u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 Python, \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442. \u042f, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e, \u0432\u044b\u0431\u0438\u0440\u0430\u044e PyCharm.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u044f\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b <code>requirements.txt<\/code>. \u0417\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"css\">fastapi==0.115.0 pydantic==2.9.2 uvicorn==0.31.0 pydantic_settings==2.7.1 loguru==0.7.2 SQLAlchemy==2.0.35 aiosqlite==0.20.0 alembic==1.14.0 httpx==0.28.1 apscheduler==3.11.0 pytz==2024.2<\/code><\/pre>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:<\/p>\n<pre><code class=\"bash\">pip install -r requirements.txt<\/code><\/pre>\n<p><strong>\u0428\u0430\u0433 2: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/strong><\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0430\u0436\u043d\u044b\u0439 \u044d\u0442\u0430\u043f \u2014 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 .env. \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0435\u0433\u043e \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438:<\/p>\n<pre><code class=\"css\">ADMIN_IDS=[12345] BASE_SITE=http:\/\/127.0.0.1:8000 BOT_TOKEN=your_bot_token TG_API_SITE=https:\/\/api.telegram.org FRONT_SITE=http:\/\/127.0.0.1:3000<\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043a\u0430\u0436\u0434\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e:<\/p>\n<ul>\n<li>\n<p><code>ADMIN_IDS<\/code> \u2014 \u0441\u043f\u0438\u0441\u043e\u043a Telegram ID \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0432\u0430\u0448\u0435\u0433\u043e \u0431\u043e\u0442\u0430. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0435\u0433\u043e ID \u0438 ID \u043b\u044e\u0431\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0438\u043c \u0431\u043e\u0442\u043e\u043c: <a href=\"https:\/\/t.me\/get_tg_ids_universeBOT\">Telegram-\u0431\u043e\u0442\u043e\u043c<\/a>.<\/p>\n<\/li>\n<li>\n<p><code>BASE_SITE<\/code> \u2014 \u0430\u0434\u0440\u0435\u0441, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u0430\u0448 FastAPI. \u0423\u043a\u0430\u0437\u0430\u043d \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430. \u041f\u0440\u0438 \u0434\u0435\u043f\u043b\u043e\u0435 \u0437\u0430\u043c\u0435\u043d\u0438\u043c \u0435\u0433\u043e \u043d\u0430 \u0442\u043e\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 <a href=\"https:\/\/amvera.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=yakvenalex_vue_fast_api_part_1\">Amvera Cloud<\/a> (\u0430\u0434\u0440\u0435\u0441 \u0431\u0435\u0437 \u0441\u043b\u0435\u0448\u0430 \u0432 \u043a\u043e\u043d\u0446\u0435).<\/p>\n<\/li>\n<li>\n<p><code>BOT_TOKEN<\/code> \u2014 \u0442\u043e\u043a\u0435\u043d \u0432\u0430\u0448\u0435\u0433\u043e Telegram-\u0431\u043e\u0442\u0430. \u0415\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/t.me\/BotFather\">BotFather<\/a>.<\/p>\n<\/li>\n<li>\n<p><code>TG_API_SITE<\/code> \u2014 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 API Telegram.<\/p>\n<\/li>\n<li>\n<p><code>FRONT_SITE<\/code> \u2014 \u0430\u0434\u0440\u0435\u0441 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0434\u043e \u043d\u0435\u0433\u043e \u043c\u044b \u0434\u043e\u0431\u0435\u0440\u0451\u043c\u0441\u044f \u043f\u043e\u0437\u0436\u0435).<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0428\u0430\u0433 3: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/strong><\/p>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0434\u0432\u0435 \u043f\u0430\u043f\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><code>data<\/code> \u2014 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 SQLite.<\/p>\n<\/li>\n<li>\n<p><code>app<\/code> \u2014 \u0434\u043b\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 FastApi \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0430\u043f\u043a\u0438 app:<\/p>\n<ul>\n<li>\n<p><code>api<\/code> \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u044d\u043d\u0434\u043f\u043e\u0438\u043d\u0442\u044b API.<\/p>\n<\/li>\n<li>\n<p><code>dao<\/code> \u2014 \u043b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 SQLAlchemy.<\/p>\n<\/li>\n<li>\n<p><code>static<\/code> \u2014 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0444\u043e\u0442\u043e \u0432\u0440\u0430\u0447\u0435\u0439).<\/p>\n<\/li>\n<li>\n<p><code>tg_bot<\/code> \u2014 \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 Telegram-\u0431\u043e\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435 \u043f\u0430\u043f\u043a\u0438 app \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0442\u0440\u0438 \u0444\u0430\u0439\u043b\u0430:<\/p>\n<ol>\n<li>\n<p><code>async_client.py<\/code> \u2014 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 HTTP-\u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c (HTTPX).<\/p>\n<\/li>\n<li>\n<p><code>config.py<\/code> \u2014 \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>main.py<\/code> \u2014 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u0428\u0430\u0433 4: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439<\/strong><\/p>\n<p>\u0417\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0444\u0430\u0439\u043b <code>app\/config.py<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"python\">import os from typing import List  from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore from apscheduler.schedulers.asyncio import AsyncIOScheduler from pydantic_settings import BaseSettings, SettingsConfigDict   class Settings(BaseSettings):     BOT_TOKEN: str     ADMIN_IDS: List[int]     FORMAT_LOG: str = \"{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}\"     LOG_ROTATION: str = \"10 MB\"     DB_URL: str = 'sqlite+aiosqlite:\/\/\/data\/db.sqlite3'     STORE_URL: str = 'sqlite:\/\/\/data\/jobs.sqlite'     BASE_SITE: str     TG_API_SITE: str     FRONT_SITE: str      model_config = SettingsConfigDict(         env_file=os.path.join(os.path.dirname(os.path.abspath(__file__)), \"..\", \".env\")     )      def get_webhook_url(self) -&gt; str:         \"\"\"\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 URL \u0432\u0435\u0431\u0445\u0443\u043a\u0430.\"\"\"         return f\"{self.BASE_SITE}\/webhook\"      def get_tg_api_url(self) -&gt; str:         \"\"\"\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 URL Telegram API.\"\"\"         return f\"{self.TG_API_SITE}\/bot{self.BOT_TOKEN}\"   # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u0430 \u0437\u0430\u0434\u0430\u0447 settings = Settings() database_url = settings.DB_URL scheduler = AsyncIOScheduler(     jobstores={'default': SQLAlchemyJobStore(url=settings.STORE_URL)} ) <\/code><\/pre>\n<p>\u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0442\u0443\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>pydantic_settings<\/code> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0418\u0437 \u043d\u043e\u0432\u043e\u0433\u043e, \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 APScheduler. \u042d\u0442\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438 \u0438 \u0438\u0445 \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c. \u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 APScheduler \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0439 \u043e \u0437\u0430\u043f\u0438\u0441\u044f\u0445 \u043a \u0434\u043e\u043a\u0442\u043e\u0440\u0430\u043c \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p><strong>\u0425\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0437\u0430\u0434\u0430\u0447.<\/strong> \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>SQLAlchemyJobStore<\/code>, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 SQLite (data\/jobs.sqlite). \u0427\u0430\u0449\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 Redis, \u043d\u043e \u044f, \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u044f, \u0440\u0435\u0448\u0438\u043b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u0434\u0430\u043d\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435.<\/p>\n<p><strong>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a.<\/strong> \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>AsyncIOScheduler<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-444897","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/444897","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=444897"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/444897\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=444897"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=444897"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=444897"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}