{"id":355086,"date":"2024-05-20T23:01:25","date_gmt":"2024-05-20T23:01:25","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=355086"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=355086","title":{"rendered":"<span>Hello-World \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u043d\u0430 React\/Django\/RabbitMQ\/Websockets<\/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>\u041e\u0434\u043d\u0430\u0436\u0434\u044b \u0432 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043d\u0430 React\/Django \u044f \u043d\u0430\u0448\u0435\u043b \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u043e\u0434\u043d\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0443\u044e <a href=\"https:\/\/habr.com\/ru\/articles\/713490\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0430\u0442\u044c\u044e.<\/a> \u041e\u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043c\u043d\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439, \u0438 \u044f \u0440\u0435\u0448\u0438\u043b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u043e\u0432\u044b\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438. \u0412 \u044d\u0442\u043e\u043c \u0441\u0438\u043a\u0432\u0435\u043b\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u0432\u0435\u0431-\u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 real-time \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 \u0441\u043e\u043a\u0435\u0442\u0430\u0445, \u0443\u043b\u0443\u0447\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 Docker-\u0441\u0431\u043e\u0440\u043a\u0438, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439 \u043d\u0430 RabbitMQ \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0433\u043b\u0430\u0434\u0438\u043c \u043a\u043e\u0441\u043c\u0435\u0442\u0438\u043a\u0443. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b.<\/p>\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0422\u0438\u043f\u043e\u0432\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f fullstack-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0441\u0442\u0435\u0439, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438, \u0431\u0440\u043e\u043a\u0435\u0440\u044b \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439, \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0431\u043e\u0440\u043a\u0438, \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0444\u0440\u043e\u043d\u0442\u043e\u0432\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, UI-\u0432\u0438\u0434\u0436\u0435\u0442\u044b \u0438 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0440\u043e\u0433\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u043e\u0432\u0438\u0447\u043a\u0430\u043c \u043f\u043e\u0440\u043e\u0439 \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0438 \u0438 \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0432 \u0435\u0434\u0438\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442. \u0426\u0435\u043b\u044c\u044e \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0438\u0437 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u0430\u0442\u044c \u043d\u0435\u043f\u043b\u043e\u0445\u043e\u0439 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u043e\u0439 \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.<\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0435 \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u0439\u0442\u0438 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<h2>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f<\/h2>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 Django, \u0444\u0440\u043e\u043d\u0442-\u044d\u043d\u0434 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 React, \u0443\u043c\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b Docker, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0441\u043d\u043e\u0432\u044b \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 Nginx. \u0422\u0430\u043a\u0436\u0435, \u0432\u0441\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u043e\u0434 \u0437\u0430\u043f\u0443\u0441\u043a \u0432 \u0441\u0440\u0435\u0434\u0435 Ubuntu 20.04. \u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0441 \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u043c\u0435\u0448\u0430\u0435\u0442 \u0432\u0430\u043c \u043f\u0440\u043e\u0439\u0442\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b, \u043d\u043e \u0432\u0441\u0435 \u0436\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u201cHello-world\u201d \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/docs.djangoproject.com\/en\/4.2\/intro\/tutorial01\/\" rel=\"noopener noreferrer nofollow\">Introduction to Django<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/react.dev\/learn\" rel=\"noopener noreferrer nofollow\">Learn React<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docker-curriculum.com\/\" rel=\"noopener noreferrer nofollow\">Introduction to Docker<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.docker.com\/blog\/how-to-use-the-official-nginx-docker-image\/\" rel=\"noopener noreferrer nofollow\">Nginx with Docker tutorial<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>\u041e\u0431\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h2>\n<p>\u041d\u0430\u0448 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Django \u0434\u043b\u044f \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0444\u0440\u043e\u043d\u0442-\u044d\u043d\u0434\u0430 \u043d\u0430 React, \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 Node.js \u0434\u043b\u044f real-time \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0445 \u0438 \u0441\u0432\u044f\u0437\u0443\u044e\u0449\u0435\u0433\u043e \u0431\u0440\u043e\u043a\u0435\u0440\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043d\u0430 RabbitMQ. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 Django Channels \u0432 ASGI-\u0440\u0435\u0436\u0438\u043c\u0435 \u0438 \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0437\u0430\u0434\u0430\u0447\u0443, \u043d\u043e \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u044b \u043e\u0431\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u043f\u043b\u044e\u0448\u0435\u043a \u0438 \u0441\u043e\u0431\u0435\u0440\u0435\u043c \u0432\u0441\u0435 \u0441\u0432\u043e\u0438\u043c\u0438 \u0440\u0443\u043a\u0430\u043c\u0438.<\/p>\n<h2>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c 3 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f, \u043e\u0442\u0440\u0430\u0436\u0430\u044e\u0449\u0438\u0445 \u0442\u0438\u043f\u043e\u0432\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<ul>\n<li>\n<p><strong>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.<\/strong> \u0414\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c <a href=\"https:\/\/www.django-rest-framework.org\/api-guide\/authentication\/#sessionauthentication\" rel=\"noopener noreferrer nofollow\">Django Session Authentication<\/a>. \u042d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0442\u043e\u043a\u0435\u043d \u0441\u0435\u0441\u0441\u0438\u0438 \u0432 \u043e\u0431\u043c\u0435\u043d \u043d\u0430 \u0441\u0432\u044f\u0437\u043a\u0443 \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c, \u0438 \u044d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u0422\u043e\u043a\u0435\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 Cookies \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0444\u0440\u043e\u043d\u0442\u0430. \u041f\u043e\u043c\u0438\u043c\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0435\u0442\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u0438 \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0438 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u043a\u0435\u043d\u0430-\u0441\u0435\u0441\u0441\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430<\/strong>. \u041f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430 \u0435\u0433\u043e \u0430\u0432\u0430\u0442\u0430\u0440  \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Django. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u044b. \u042d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 Worker (\u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u043d\u044b\u0439 \u0432 \u0432\u0438\u0434\u0435 <a href=\"https:\/\/docs.djangoproject.com\/en\/4.2\/howto\/custom-management-commands\/\" rel=\"noopener noreferrer nofollow\">Django management command<\/a>), \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 Django. \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0439 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u043e\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u0438\u0437 Django \u0432 Worker \u0447\u0435\u0440\u0435\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u044c RabbitMQ (\u043a\u043b\u044e\u0447 to_resize).<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0445.<\/strong> \u041f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0432\u0441\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0438 \u0436\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u044d\u0442\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Node.js, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043a\u043b\u044e\u0447\u043e\u043c to_sockets, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 \u0438\u0437 Worker-\u0430 \u0447\u0435\u0440\u0435\u0437 RabbitMQ.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u0412\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/807\/8b9\/83f\/8078b983f890543f9c3e62f895f661a5.png\" width=\"1111\" height=\"614\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/807\/8b9\/83f\/8078b983f890543f9c3e62f895f661a5.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h2>\n<p>\u0422\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u2014 \u044d\u0442\u043e \u0437\u0430\u043b\u043e\u0433 \u043a\u043e\u043c\u0444\u043e\u0440\u0442\u043d\u043e\u0439 \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u043c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e\u0439 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 Django \u0438 Webpack\/React, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u043a\u0438 \u0432 \u043a\u043e\u0434\u0435 \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u0440\u0430\u0436\u0430\u043b\u0438\u0441\u044c \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043b\u044e\u0431\u044b\u0445 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 (Nginx, RabbitMQ, PostgreSQL). \u041a\u0440\u043e\u043c\u0435 \u044d\u0442\u043e\u0433\u043e, \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0435\u0441\u043b\u0438 \u0441\u0440\u0435\u0434\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0431\u044b\u043b\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e Django, Node.js \u0438 \u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445. \u0412 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0436\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0439 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u0448\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439.<\/p>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 1 &#8212; \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e<\/strong>. \u041e\u0434\u0438\u043d \u0438\u0437 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u2014 \u044d\u0442\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0430 \u0442\u0435 endpoint-\u044b, \u0433\u0434\u0435 \u043e\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f, \u0442.\u0435. REST-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 Django-\u0441\u0435\u0440\u0432\u0435\u0440, index.html \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 Webpack-\u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u0441\u043e\u043a\u0435\u0442\u044b \u043d\u0430 \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440. \u0422\u0430\u043a\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u201c\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438\u201d \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 (Nginx). \u041d\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c CORS-\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 Header-\u044b (Allowed Hosts \u0438 \u043f\u0440.), \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u044e\u0442\u0441\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u043e\u0439 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0432 \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0446\u0438\u044e endpoint-\u043e\u0432 \u0432 React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u0444\u0440\u043e\u043d\u0442-\u044d\u043d\u0434 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u043b\u0441\u044f \u0432 production-\u0440\u0435\u0436\u0438\u043c \u0438 \u0441\u0442\u0443\u0447\u0430\u043b\u0441\u044f \u043d\u0430 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0430\u0434\u0440\u0435\u0441\u0430. \u0412\u0441\u0435 \u044d\u0442\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c, \u043d\u043e \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0442 \u043d\u0430\u0448\u0435\u0439 \u0446\u0435\u043b\u0438 \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0440\u0435\u0434\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0432\u0430\u0440\u0438\u0430\u043d\u0442 1 &#8212; \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/be1\/02c\/52c\/be102c52cceec3115f92ca702a44e042.png\" width=\"1413\" height=\"805\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/be1\/02c\/52c\/be102c52cceec3115f92ca702a44e042.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 2 (\u0447\u0435\u0440\u0435\u0437 Webpack proxy)<\/strong>. \u0411\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0433\u043e webpack-proxy, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u043d\u0430 Webpack \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043b\u0438\u0431\u043e \u043d\u0430 REST-\u0441\u0435\u0440\u0432\u0435\u0440 Django, \u043b\u0438\u0431\u043e \u043d\u0430 \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u043b\u0438\u0431\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0438\u0437 \u0441\u0442\u0430\u0442\u0438\u043a\u0438. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u044d\u043d\u0434\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0441\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0443 (\u0442.\u0435. \u0432\u0441\u0435 endpoint-\u044b \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438), \u043d\u043e \u043c\u043e\u0433\u0443\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043e\u043a\u0435\u0442\u043d\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f (\u0441\u043c. <a href=\"https:\/\/github.com\/facebook\/create-react-app\/issues\/5280\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0443<\/a> \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0443). \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u043e\u0441\u0438\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u043c\u044b\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440, \u043c\u044b \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0435\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 Nginx. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0432\u0430\u0440\u0438\u0430\u043d\u0442 2 &#8212; \u0447\u0435\u0440\u0435\u0437 Webpack proxy)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0a8\/a63\/122\/0a8a631226411090df7353edafc84193.png\" width=\"1459\" height=\"629\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0a8\/a63\/122\/0a8a631226411090df7353edafc84193.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 3 &#8212; \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 (\u0447\u0435\u0440\u0435\u0437 nginx)<\/strong>. \u041d\u0430\u0448\u0430 \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c Nginx \u043a\u0430\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041f\u043e\u043c\u0438\u043c\u043e \u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0440\u0435\u0436\u0438\u043c\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 Nginx, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/docs.nginx.com\/nginx\/admin-guide\/security-controls\/configuring-subrequest-authentication\/\" rel=\"noopener noreferrer nofollow\">auth_request<\/a> \u0438 \u043a\u043b\u044e\u0447\u0430 \u0441\u0435\u0441\u0441\u0438\u0438. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u043e\u0442\u043b\u0430\u0434\u0438\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u043a\u0435\u0442\u043e\u0432.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0432\u0430\u0440\u0438\u0430\u043d\u0442 3 &#8212; \u0447\u0435\u0440\u0435\u0437 Nginx)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0b6\/892\/dc0\/0b6892dc070f2566785e154572c86345.png\" width=\"1457\" height=\"809\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0b6\/892\/dc0\/0b6892dc070f2566785e154572c86345.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 4 (\u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f)<\/strong>. \u0412 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Django \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0432 production-\u0440\u0435\u0436\u0438\u043c\u0435 (DEBUG=False), \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0434\u0438\u0430-\u0441\u0442\u0430\u0442\u0438\u043a\u0438 (\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0430\u0432\u0430\u0442\u0430\u0440\u043e\u0432 \u0432 \u043f\u0430\u043f\u043a\u0435 media) \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0438 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0443 \u043c\u0435\u0434\u0438\u0430-\u0441\u0442\u0430\u0442\u0438\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 Nginx. \u0422\u0430\u043a\u0436\u0435, bundle-\u0441\u0431\u043e\u0440\u043a\u0430 React \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Nginx \u0438 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0439 Webpack-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f. \u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u0431\u0443\u0434\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0442\u0438\u043f\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0411\u0414 \u0441 SQLite \u043d\u0430 Postgres, \u043d\u043e \u043e\u043d\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0443\u0436\u0435 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/727\/33b\/77f\/72733b77fd1dfe10da36d7456d75edcd.png\" width=\"1444\" height=\"624\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/727\/33b\/77f\/72733b77fd1dfe10da36d7456d75edcd.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 &#8212; Docker, Docker-compose, Python3.10, Pip, Django:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 1 &#8212; \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\"># Docker sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common curl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | sudo apt-key add - sudo add-apt-repository \"deb [arch=amd64] https:\/\/download.docker.com\/linux\/ubuntu $(lsb_release -cs) stable\" sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io  # Docker-compose v1 sudo curl -L \"https:\/\/github.com\/docker\/compose\/releases\/download\/1.25.5\/docker-compose-$(uname -s)-$(uname -m)\" -o \/usr\/local\/bin\/docker-compose sudo chmod +x \/usr\/local\/bin\/docker-compose sudo ln -s \/usr\/local\/bin\/docker-compose \/usr\/bin\/docker-compose  # Python3.10 + Pip sudo apt install software-properties-common sudo add-apt-repository ppa:deadsnakes\/ppa sudo apt install python3.10 curl -sS https:\/\/bootstrap.pypa.io\/get-pip.py | python3.10  # Django pip install django==4.2.4<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0436\u0435, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f node.js. \u041d\u043e \u043c\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437 \u0441\u0440\u0435\u0434\u0443 nvm, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043d\u043e\u0434\u044b.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 2 &#8212; \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 node.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">curl https:\/\/raw.githubusercontent.com\/creationix\/nvm\/master\/install.sh | bash source ~\/.bashrc nvm install 18.16.0<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u043f\u0430\u043f\u043a\u0443 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u0438 \u0437\u0430\u0432\u0435\u0434\u0435\u043c \u0432 \u043d\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043d\u0430 Django \u0438 React, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u0434\u043f\u0430\u043f\u043a\u0438 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 (\u0430\u0432\u0430\u0442\u0430\u0440\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439). \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 React \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 create-react-app, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c boilerplate-\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043a\u0430\u043a Webpack (\u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0438 \u0441\u0431\u043e\u0440\u043a\u0438 js-\u043f\u0440\u043e\u0435\u043a\u0442\u0430) \u0438 Babel (\u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043f\u0438\u043b\u044f\u0446\u0438\u0438 js-\u043a\u043e\u0434\u0430, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044e\u0449\u0435\u0439 \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0441 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u043c\u0438 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432).<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 3 &#8212; \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\"># \u041f\u0430\u043f\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mkdir demo cd demo  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 django-admin startproject django_project  # \u041f\u0430\u043f\u043a\u0438 \u0434\u043b\u044f media-\u0444\u0430\u0439\u043b\u043e\u0432 mkdir django_project\/media mkdir django_project\/media\/photo  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f React-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 npm install create-react-app npx create-react-app reactapp<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041c\u043e\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0441\u0440\u0430\u0437\u0443 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043f\u0430\u043f\u043a\u0438 <code>\/demo\/node_modules<\/code> \u0438 \u0444\u0430\u0439\u043b\u044b <code>\/demo\/package.json<\/code> \u0438 <code>\/demo\/package-lock.json<\/code>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c\u0441\u044f \u0441 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c\u0438 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>\/demo\/reactapp<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 4 &#8212; \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">rm -rf node_modules\/ rm package.json rm package-lock.json<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u043f\u043a\u0443 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a nginx \u0432 \u0440\u0435\u0436\u0438\u043c\u0430\u0445 development \u0438 production.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 5 &#8212; \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 nginx<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">mkdir nginx mkdir nginx\/development mkdir nginx\/production<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/nginx\/development\/nginx.conf<\/code> \u0437\u0430\u0432\u0435\u0434\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 6 &#8212; \/demo\/nginx\/development\/nginx.conf<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"nginx\">server {     listen 80;     server_name _;     server_tokens off;     client_max_body_size 20M;      location \/ {         proxy_pass http:\/\/ 172.17.0.1:3000\/;     }      location \/api {         try_files $uri @proxy_api;     }     location \/admin {         try_files $uri @proxy_api;     }      location @proxy_api {         proxy_set_header X-Forwarded-Proto https;         proxy_set_header X-Url-Scheme $scheme;         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header Host $http_host;         proxy_redirect off;         proxy_pass   http:\/\/ 172.17.0.1:8000;     }      location \/media {         autoindex on;         alias \/app\/backend\/server\/media\/;     }      location \/django_static\/ {         autoindex off;         alias \/app\/backend\/server\/django_static\/;     }      location \/ws {         auth_request \/auth;         proxy_pass http:\/\/ 172.17.0.1:8010\/;         proxy_http_version 1.1;         proxy_set_header Upgrade $http_upgrade;                 proxy_set_header Connection \"upgrade\";     }      location \/auth {         proxy_set_header Content-Type 'application\/json;charset=utf-8';         proxy_pass http:\/\/ 172.17.0.1:8000\/api\/students\/;     }   }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<ul>\n<li>\n<p>\u0412\u0441\u0435 \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b <code>\/<\/code> \u043f\u043e\u0439\u0434\u0443\u0442 \u043d\u0430 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0439 Webpack \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 3000, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u043a\u0443 React-\u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Nginx \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435, \u0442\u043e \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443, \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u043c\u0443 \u043d\u0430 \u0445\u043e\u0441\u0442\u043e\u0432\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0430\u0434\u0440\u0435\u0441 <code>http:\/\/172.17.0.1:3000\/<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u043f\u0443\u0442\u044c <code>\/api<\/code> (REST API Django) \u0438 <code>\/admin<\/code> (Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0430) \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Django \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 8000 \u0447\u0435\u0440\u0435\u0437 <code>@proxy_api<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u043c\u0435\u0434\u0438\u0430-\u0441\u0442\u0430\u0442\u0438\u043a\u0443 (\u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0438) \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f Nginx \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0430\u043f\u043a\u0438 <code>\/app\/backend\/server\/media<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043f\u0440\u043e\u0431\u0440\u043e\u0441\u0438\u043c \u0447\u0435\u0440\u0435\u0437 Docker Unnamed Volume \u043a \u043f\u0430\u043f\u043a\u0435 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c Django \u043d\u0430 \u0445\u043e\u0441\u0442\u043e\u0432\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435;<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 Django-\u0441\u0442\u0430\u0442\u0438\u043a\u0443 <code>\/django_static<\/code> \u0434\u043b\u044f \u0434\u0436\u0430\u043d\u0433\u043e\u0432\u0441\u043a\u043e\u0439 \u0430\u0434\u043c\u0438\u043d\u043a\u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u0438\u043c \u0432 \u043f\u0430\u043f\u043a\u0443 \u043d\u0430 \u0445\u043e\u0441\u0442\u043e\u0432\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440 Node.js <code>\/ws<\/code> \u0431\u0443\u0434\u0443\u0442 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u0445\u043e\u0441\u0442\u043e\u0432\u044b\u0439 \u043f\u043e\u0440\u0442 8010. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0441\u0442\u043e\u0438\u0442 \u043e\u0441\u043e\u0431\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u0443\u044e \u0440\u0430\u043d\u0435\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0443 <code>auth_request<\/code> \u2013 \u043e\u043d\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u043e\u043a\u0435\u0442\u043d\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043f\u0443\u0442\u0435\u043c \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 endpoint <code>\/auth<\/code> (\u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430 \u043f\u0443\u0442\u044c <code>\/api\/students\/<\/code> \u0432 Django) \u0441 \u0442\u0435\u043c\u0438 \u0436\u0435 Cookie-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0448\u043b\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u043a\u0435\u0442\u043d\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f, \u043f\u0440\u0438\u0447\u0435\u043c \u0432 \u043d\u0438\u0445 \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u043a\u043b\u044e\u0447 \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c \u0441\u0435\u0441\u0441\u0438\u0438. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 <code>auth_requst<\/code> \u0432\u0435\u0440\u043d\u0435\u0442 \u043a\u043e\u0434 200 (\u0442.\u0435. \u0437\u0430\u043f\u0440\u043e\u0441 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0439), \u0442\u043e \u0441\u043e\u043a\u0435\u0442\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u043d\u0430 \u0445\u043e\u0441\u0442\u043e\u0432\u044b\u0439 \u043f\u043e\u0440\u0442 8010 Node.js, \u0432 \u0438\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0431\u0440\u043e\u0448\u0435\u043d\u043e \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 Nginx. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u043a\u0435\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u0441\u0435\u0441\u0441\u0438\u0438 \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Node.js.<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c <code>\/demo\/dev.docker-compose.yml<\/code> \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 7 &#8212; \/demo\/dev.docker-compose.yml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">version: '2'  services:     nginx:          restart: unless-stopped         container_name: demo_nginx         build:             context: .             dockerfile: .\/Dockerfile.nginx         ports:             - 80:80         volumes:             - .\/django_project\/django_static:\/app\/backend\/server\/django_static             - .\/django_project\/media:\/app\/backend\/server\/media             - .\/nginx\/development:\/etc\/nginx\/conf.d      rmq:         image: rabbitmq:3.10-management         restart: always         container_name: demo_rmq         environment:           - RABBITMQ_DEFAULT_USER=${RMQ_USER}           - RABBITMQ_DEFAULT_PASS=${RMQ_PASS}         volumes:           - rabbitmq_data_volume:\/var\/lib\/rabbitmq\/         ports:           - 1234:15672           - 5671-5672:5671-5672         env_file:             - .\/.env  volumes:     static_volume: {}     rabbitmq_data_volume: {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u0430\u043a \u043c\u044b \u0438 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e 2 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u2013 Nginx \u0438 RabbitMQ. \u0414\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 Nginx \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b Dockerfile.nginx, \u0447\u0442\u043e\u0431\u044b \u0432 \u043d\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u0441\u043e\u0431\u0438\u0440\u0430\u043b\u0430\u0441\u044c \u0441\u0442\u0430\u0442\u0438\u043a\u0430 \u0434\u043b\u044f React \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0434\u043b\u044f production-\u0440\u0435\u0436\u0438\u043c\u0430). \u0422\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u043f\u0430\u043f\u043a\u0438 media \u0438 django_static \u0434\u043b\u044f \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u0435\u0434\u0438\u0430 \u0438 \u0441\u0442\u0430\u0442\u0438\u043a\u0438 \u0430\u0434\u043c\u0438\u043d\u043a\u0438 (\u043a\u0430\u043a \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u0448\u0435) \u0438 \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u043f\u0443\u0442\u044c \u043a development\/nginx.conf.<\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 RabbitMQ \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 \u0431\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e Dockerfile, \u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043b\u043e\u0433\u0438\u043d\u0430 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u043e\u0434\u0433\u0440\u0443\u0437\u0438\u043c \u0438\u0437 .env \u0444\u0430\u0439\u043b\u0430.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>\/demo\/Dockerfile.nginx<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 8 &#8212; \/demo\/Dockerfile.nginx<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">FROM node:18.16.0-alpine as build  WORKDIR \/app\/frontend COPY .\/reactapp\/package.json .\/ COPY .\/reactapp\/package-lock.json .\/ RUN npm ci --silent COPY .\/reactapp\/ .\/ RUN npm run build  FROM nginx:stable-alpine COPY --from=build \/app\/frontend\/build \/usr\/share\/nginx\/html CMD [\"nginx\", \"-g\", \"daemon off;\"]<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442.\u043d. \u0434\u0432\u0443\u0445-\u044d\u0442\u0430\u043f\u043d\u0430\u044f (2 stage) Docker-\u0441\u0431\u043e\u0440\u043a\u0430, \u0442.\u0435. \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u0442\u0438\u043a\u0430 React \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0430 \u043f\u043e\u0442\u043e\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0441\u0431\u043e\u0440\u043a\u0438 \u043a\u043b\u0430\u0434\u0443\u0442\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 Nginx. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0442\u044f\u043d\u0443\u0442\u044c \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u043b\u0438\u0448\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0437\u0430\u0432\u0435\u0434\u0435\u043c \u0444\u0430\u0439\u043b \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f <code>\/demo\/.env<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 9 &#8212; \/demo\/.env<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\"># \u041f\u043e\u043c\u0435\u043d\u044f\u0442\u044c! SECRET_KEY=a38d5044-e78a-416e-9bde-8aeabc598286  DEBUG=0  ALLOWED_HOSTS=*  # \u041f\u043e\u043c\u0435\u043d\u044f\u0442\u044c POSTGRES_USER \u0438 POSTGRES_PASSWORD! POSTGRES_ENGINE=django.db.backends.postgresql POSTGRES_DB=django_db POSTGRES_USER=admin POSTGRES_PASSWORD=password POSTGRES_HOST=postgres POSTGRES_PORT=5432 DATABASE=postgres  # \u041f\u043e\u043c\u0435\u043d\u044f\u0442\u044c RMQ_USER \u0438 RMQ_PASS! RMQ_HOST=rmq RMQ_PORT=5672 RMQ_USER=admin RMQ_PASS=admin<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0439\u0442\u0435 SECRET_KEY, \u043e\u043d \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e Django \u0411\u0414, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0430\u0440\u043e\u043b\u0438 \u043e\u0442 RabbitMQ (\u0441\u0435\u043a\u0446\u0438\u044f RMQ) \u0438 POSTGRES.<\/p>\n<h2>Django \u043f\u0440\u043e\u0435\u043a\u0442<\/h2>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0443. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 students \u0432\u043d\u0443\u0442\u0440\u0438 Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 10 &#8212; \u0441\u043e\u0437\u0434\u0430\u0435\u043c Django \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (students)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\"># \u0412 \u043f\u0430\u043f\u043a\u0435 demo\/django_project python manage.py startapp students<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/django_project\/students\/models.py<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 11 &#8212; \/demo\/django_project\/students\/models.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from django.db import models  class Student(models.Model):     name = models.CharField(\"Name\", max_length=240)     email = models.EmailField()     document = models.CharField(\"Document\", max_length=20)     phone = models.CharField(max_length=20)     registrationDate = models.DateField(\"Registration Date\", auto_now_add=True)     photo = models.CharField(\"URL\", max_length=512)      def __str__(self):         return self.name<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u0438\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438. \u041e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f \u0440\u0435\u0436\u0438\u043c\u0430 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0432 \u0431\u0430\u0437\u0435 SQLite. \u0414\u043b\u044f \u043f\u0440\u043e\u0433\u043e\u043d\u0430 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u0432 Postgresql \u0432 production-\u0440\u0435\u0436\u0438\u043c\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Dockerfile, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e \u043f\u043e\u0437\u0436\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 12 &#8212; \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">python manage.py makemigrations python manage.py migrate<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c, \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u043e\u0439 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438.<\/p>\n<p>\u0417\u0430\u0432\u0435\u0434\u0435\u043c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/django_project\/fixtures\/student.json<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 13 &#8212; \/demo\/django_project\/fixtures\/student.json<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">[ {     \"model\": \"students.student\",     \"pk\": 1,     \"fields\": {         \"name\": \"Mark Castillo\",         \"email\": \"mark.castillo@example.com\",         \"document\": \"---\",         \"phone\": \"(790) 550-2323\",         \"registrationDate\": \"2023-08-29\",         \"photo\": \"\/media\/photo\/f5bd4ecb-aaf7-4d4c-ade3-c35c289297d7.jpeg\"     } }, {     \"model\": \"students.student\",     \"pk\": 2,     \"fields\": {         \"name\": \"Margie Marshall\",         \"email\": \"margie.marshall@example.com\",         \"document\": \"---\",         \"phone\": \"(522) 796-6968\",         \"registrationDate\": \"2023-08-29\",         \"photo\": \"\/media\/photo\/5fad3cb0-e7c2-4074-a869-1502a8c517d3.jpeg\"     } }, {     \"model\": \"students.student\",     \"pk\": 3,     \"fields\": {         \"name\": \"Kylie Bishop\",         \"email\": \"kylie.bishop@example.com\",         \"document\": \"---\",         \"phone\": \"(732) 324-6893\",         \"registrationDate\": \"2023-08-30\",         \"photo\": \"\/media\/photo\/93d42334-cce8-4a2e-a54f-bcff9bdf4dc7.jpeg\"     } }, {     \"model\": \"students.student\",     \"pk\": 4,     \"fields\": {         \"name\": \"Carlos Hudson\",         \"email\": \"carlos.hudson@example.com\",         \"document\": \"---\",         \"phone\": \"(801) 431-1682\",         \"registrationDate\": \"2023-09-02\",         \"photo\": \"\/media\/photo\/3c4894e5-5202-45b3-ad65-9ae4ec5e1eda.jpeg\"     } } ]<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u043f\u0440\u043e\u0433\u0440\u0443\u0437\u0438\u043c \u0438\u0445 \u0432 \u0431\u0430\u0437\u0443<\/p>\n<pre><code class=\"bash\">python manage.py loaddata fixtures\/students.json --app students<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c View \u0432 \u043f\u0430\u043f\u043a\u0435 <code>\/demo\/django_project\/students\/views.py<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 14 &#8212; \/demo\/django_project\/students\/views.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from rest_framework.response import Response from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny from django.contrib.auth import authenticate, login, logout from rest_framework import status from .serializers import * from utils import connect import uuid import base64 import json  _, channel = connect()  @api_view(['POST',]) @permission_classes([AllowAny]) def login_view(request):     serializer = LoginRequestSerializer(data=request.data)     if serializer.is_valid():         authenticated_user = authenticate(**serializer.validated_data)         if authenticated_user is not None:             login(request, authenticated_user)             return Response({'status': 'Success'})         else:             return Response({'error': 'Invalid credentials'}, status=403)     else:         return Response(serializer.errors, status=400)  def logout_view(request):     logout(request)  @api_view(['GET', 'POST']) def students_list(request):     if request.method == 'GET':         data = Student.objects.all()         serializer = StudentSerializer(data, context={'request': request}, many=True)         return Response(serializer.data)     elif request.method == 'POST':         serializer = StudentSerializer(data=request.data)         if serializer.is_valid():             student = serializer.save()             if bool(request.FILES.get('file', False)) == True:                 save_image(student.pk, request.FILES['file'])             return Response(status=status.HTTP_201_CREATED)         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)  @api_view(['PUT', 'DELETE']) def students_detail(request, pk):     try:         student = Student.objects.get(pk=pk)     except Student.DoesNotExist:         return Response(status=status.HTTP_404_NOT_FOUND)     if request.method == 'PUT':         serializer = StudentSerializer(student, data=request.data, context={'request': request})         if serializer.is_valid():             serializer.save()             if bool(request.FILES.get('file', False)) == True:                 save_image(student.pk, request.FILES['file'])             return Response(status=status.HTTP_204_NO_CONTENT)         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)     elif request.method == 'DELETE':         student.delete()         return Response(status=status.HTTP_204_NO_CONTENT)  def save_image(pk, file):     global channel     filename = str(uuid.uuid4()) + '.' + file.name[file.name.rfind(\".\") + 1:]     msg = {\"filename\": filename, \"image\": base64.b64encode(file.read()).decode(\"UTF-8\"), \"pk\": pk}     try:         if (channel == None) or (channel.is_open == False):              _, channel = connect(retry = False)         if (channel != None) and (channel.is_open == True):             channel.basic_publish(exchange='', routing_key='to_resize', \\                     body=bytes(json.dumps(msg), \"UTF-8\"))     except:         print(\"Connection error\")<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0442\u0438\u043f\u043e\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043d\u0430 \u0438 \u043b\u043e\u0433\u0430\u0443\u0442\u0430. \u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u0430\u0440\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u0414\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 <code>permission_classes([AllowAny])<\/code> \u043f\u0435\u0440\u0435\u0434 \u043c\u0435\u0442\u043e\u0434\u043e\u043c login_view \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 SessionAuth, \u0438\u043d\u0430\u0447\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043b\u043e\u0433\u0438\u043d\u0438\u0442\u044c\u0441\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f channel \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 RabbitMQ. \u041e\u043d \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043d\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u044b \u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 save_image().<\/p>\n<\/li>\n<li>\n<p>\u0421\u0430\u043c \u043c\u0435\u0442\u043e\u0434 save_image() \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u0430\u0445 student_list \u0438  students_detail \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u0432 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0430. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u043a\u0430\u043d\u0430\u043b\u0443 RabbitMQ \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 channel.basic_publish().<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u044f\u0441\u043d\u0438\u0442\u044c \u0447\u0442\u043e \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c Django \u0432 WSGI \u0440\u0435\u0436\u0438\u043c\u0435, \u0442\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u043c \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0435\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a RabbitMQ, \u043e\u043d\u043e \u043d\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 heartbeat-\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430 heartbeat-\u0430 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0442\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f. \u0412 \u0441\u0432\u044f\u0437\u0438 \u0441 \u044d\u0442\u0438\u043c \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 save_image \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0438 \u0435\u0441\u043b\u0438 \u043e\u043d\u043e \u0440\u0430\u0437\u043e\u0440\u0432\u0430\u043d\u043e, \u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435. \u0421\u0430\u043c \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440 \u043a\u0430\u043d\u0430\u043b\u0430 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 channel, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 REST-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u043a\u0430 \u043e\u043d\u043e \u043d\u0435 \u0440\u0430\u0437\u043e\u0440\u0432\u0430\u043b\u043e\u0441\u044c. \u0415\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0432\u0435\u043b\u0438\u043a\u043e, \u0442\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0438\u0445 \u0438\u0437\u0434\u0435\u0440\u0436\u0435\u043a \u043d\u0430 \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f. \u0410 \u0435\u0441\u043b\u0438 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430 heartbeat-\u043e\u0432 \u043d\u0435 \u043f\u0440\u0438\u0434\u0435\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0442\u043e \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435 \u0437\u0430\u0439\u043c\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 RabbitMQ \u0438 Django \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0444\u0430\u0439\u043b <code>\/demo\/django_project\/utils.py<\/code> \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u043c\u0435\u0442\u043e\u0434 connect(), \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0444\u0430\u0439\u043b\u0435 <a href=\"http:\/\/views.py\" rel=\"noopener noreferrer nofollow\">views.py<\/a>, \u043d\u043e \u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Worker-\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 15 &#8212; \/demo\/django_project\/utils.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from django.conf import settings import pika import time  def connect(queues = [\"to_resize\", \"to_socket\"], retry = True):     connected = False     while connected == False:         try:             credentials = pika.PlainCredentials(username=settings.RMQ_USER,                 password=settings.RMQ_PASS)             parameters = pika.ConnectionParameters(host=settings.RMQ_HOST,                 port=settings.RMQ_PORT, credentials=credentials)             connection = pika.BlockingConnection(parameters=parameters)             channel = connection.channel()             for queue in queues:                 channel.queue_declare(queue = queue)             connected = True             return connection, channel         except:             pass         if retry == False: return None, None         time.sleep(5)<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u043b\u0435\u0435, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Worker-\u0430. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441 Django \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 RabbitMQ. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0441 \u043a\u043b\u044e\u0447\u043e\u043c to_resize \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0441\u0436\u0430\u0442\u0438\u0435 \u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0438 \u0432 \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u0443, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f to_socker \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 RabbitMQ (\u0434\u043b\u044f \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 socket-\u043a\u043b\u0438\u0435\u043d\u0442\u044b) \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044f photo \u0432 \u0411\u0414.<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0444\u0430\u0439\u043b\u0430 <code>\/demo\/django_project\/students\/management\/commands\/worker.py<\/code>. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c Worker \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 python <a href=\"http:\/\/manage.py\" rel=\"noopener noreferrer nofollow\">manage.py<\/a> worker, \u043c\u044b \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0435\u0435 \u0432 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0434\u0430\u043b\u0435\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 16 &#8212; \/demo\/django_project\/students\/management\/commands\/worker.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from students.models import Student from django.core.management.base import BaseCommand from django.conf import settings from PIL import Image from utils import connect import io import os from io import BytesIO import urllib.parse import base64 import pika import time import json  class Command(BaseCommand):     def handle(self, *args, **options):         connection, channel = connect()         print(\"I am DJANGO WORKER and I am Waiting for messages. To exit press CTRL+C\")         channel.basic_consume(queue='to_resize', auto_ack=True,\\                 on_message_callback=self.callback)         channel.start_consuming()      @staticmethod     def callback(ch, method, properties, body):         try:             print(\"Processing image 'to_resize'\")             msg = json.loads(body.decode(\"UTF-8\"))             filepath = os.path.join(settings.MEDIA_ROOT, 'photo\/', msg[\"filename\"])             fixed_height = 300             image = Image.open(BytesIO(base64.b64decode(msg[\"image\"])))             height_percent = (fixed_height \/ float(image.size[1]))             width_size = int((float(image.size[0]) * float(height_percent)))             new = image.resize((width_size, fixed_height))             image.save(filepath)             student = Student.objects.get(pk=msg[\"pk\"])             student.photo = settings.MEDIA_URL + \"photo\/\" + msg[\"filename\"]             student.save(update_fields=['photo'])             socket_msg = {\"type\": \"refresh\"}             ch.basic_publish(exchange='', routing_key='to_socket',\\                     body=bytes(json.dumps(socket_msg), \"UTF-8\"))             print(\"Processing image 'to_resize' complete\")         except Exception as error:             print(error)<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Serializer \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/django_project\/students\/serializers.py<\/code> \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u0438 \u043b\u043e\u0433\u0438\u043d\u0430\/\u043f\u0430\u0440\u043e\u043b\u044f \u043f\u0440\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 17 &#8212; \/demo\/django_project\/students\/serializers.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from rest_framework.serializers import ModelSerializer, Serializer, CharField from django.contrib.auth.models import User from .models import Student  class StudentSerializer(ModelSerializer):      class Meta:         model = Student         fields = ('pk', 'name', 'email', 'document', 'phone', 'registrationDate','photo')  class LoginRequestSerializer(Serializer):     model = User     username = CharField(required=True)     password = CharField(required=True)<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0427\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u0432 \u0430\u0434\u043c\u0438\u043d\u043a\u0435 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/django_project\/students\/admin.py:<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 18 &#8212; \/demo\/django_project\/students\/admin.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from django.contrib import admin from .models import Student  admin.site.register(Student)<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0443\u0442\u0438\u043d\u0433\u0430 URL \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/django_project\/django_project\/urls.py<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 19 &#8212; \/demo\/django_project\/django_project\/urls.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from django.contrib import admin from django.urls import path, re_path from students import views from django.conf import settings from django.conf.urls.static import static from django.contrib.auth.views import LogoutView  urlpatterns = [     path('admin\/', admin.site.urls),     path('api\/login', views.login_view, name='login'),     path('api\/logout', LogoutView.as_view(next_page='\/'), name='logout'),     re_path(r'^api\/students\/$', views.students_list),     re_path(r'^api\/students\/(\\d+)$', views.students_detail), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043c\u0430\u043f\u0438\u043d\u0433\u0438 URL-\u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u0432\u043e <a href=\"http:\/\/views.py\" rel=\"noopener noreferrer nofollow\">views.py<\/a>. \u0422\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430 logout \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 LogoutView \u0438\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 django.contrib.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u043e\u0431\u043d\u043e\u0432\u0438\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 <code>\/demo\/django_project\/django_project\/settings.py<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 20 &#8212; \/demo\/django_project\/django_project\/settings.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import os from pathlib import Path from os import environ  BASE_DIR = Path(__file__).resolve().parent.parent  SECRET_KEY = environ.get('SECRET_KEY', \"82c1e306-2cdc-412c-9f0e-1ae9fae14126\")  DEBUG = int(environ.get('DEBUG', default = 1))  ALLOWED_HOSTS = environ.get('ALLOWED_HOSTS', '*').split(' ')  if \"CSRF_TRUSTED_ORIGINS\" in environ:     CSRF_TRUSTED_ORIGINS = environ.get('CSRF_TRUSTED_ORIGINS').split(' ')  RMQ_HOST = environ.get('RMQ_HOST', '127.0.0.1') RMQ_PORT = environ.get('RMQ_PORT', 5672) RMQ_USER = environ.get('RMQ_USER', 'admin') RMQ_PASS = environ.get('RMQ_PASS', 'admin')  INSTALLED_APPS = [     'django.contrib.admin',     'django.contrib.auth',     'django.contrib.contenttypes',     'django.contrib.sessions',     'django.contrib.messages',     'django.contrib.staticfiles',     'rest_framework',     'students' ]  MIDDLEWARE = [     'django.middleware.security.SecurityMiddleware',     'django.contrib.sessions.middleware.SessionMiddleware',     'django.middleware.common.CommonMiddleware',     'django.middleware.csrf.CsrfViewMiddleware',     'django.contrib.auth.middleware.AuthenticationMiddleware',     'django.contrib.messages.middleware.MessageMiddleware',     'django.middleware.clickjacking.XFrameOptionsMiddleware', ]   ROOT_URLCONF = 'django_project.urls'  TEMPLATES = [     {         'BACKEND': 'django.template.backends.django.DjangoTemplates',         'DIRS': [],         'APP_DIRS': True,         'OPTIONS': {             'context_processors': [                 'django.template.context_processors.debug',                 'django.template.context_processors.request',                 'django.contrib.auth.context_processors.auth',                 'django.contrib.messages.context_processors.messages',             ],         },     }, ]  WSGI_APPLICATION = 'django_project.wsgi.application'   # Database # https:\/\/docs.djangoproject.com\/en\/4.2\/ref\/settings\/#databases  DATABASES = {     'default': {         'ENGINE': environ.get('POSTGRES_ENGINE', 'django.db.backends.sqlite3'),         'NAME': environ.get('POSTGRES_DB', BASE_DIR \/ 'db.sqlite3'),         'USER': environ.get('POSTGRES_USER', 'user'),         'PASSWORD': environ.get('POSTGRES_PASSWORD', 'password'),         'HOST': environ.get('POSTGRES_HOST', 'localhost'),         'PORT': environ.get('POSTGRES_PORT', '5432'),     } }   # Password validation # https:\/\/docs.djangoproject.com\/en\/4.2\/ref\/settings\/#auth-password-validators  AUTH_PASSWORD_VALIDATORS = [     {         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',     },     {         'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',     },     {         'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',     },     {         'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',     }, ]   # Internationalization # https:\/\/docs.djangoproject.com\/en\/4.2\/topics\/i18n\/  LANGUAGE_CODE = 'en-us'  TIME_ZONE = 'UTC'  USE_I18N = True  USE_TZ = True   # Static files (CSS, JavaScript, Images) # https:\/\/docs.djangoproject.com\/en\/4.2\/howto\/static-files\/  STATIC_URL = 'django_static\/' STATIC_ROOT = os.path.join(BASE_DIR, 'django_static')  MEDIA_URL = 'media\/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')  # Default primary key field type # https:\/\/docs.djangoproject.com\/en\/4.2\/ref\/settings\/#default-auto-field  DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'  REST_FRAMEWORK = {     'DEFAULT_AUTHENTICATION_CLASSES': [         'rest_framework.authentication.SessionAuthentication',     ],     'DEFAULT_PERMISSION_CLASSES': [         'rest_framework.permissions.IsAuthenticated',     ], }  LOGGING = {     'version': 1,     'disable_existing_loggers': False,     'filters': {         'require_debug_true': {             '()': 'django.utils.log.RequireDebugTrue',         }     },     'handlers': {         'console': {             'level': 'INFO',             'filters': ['require_debug_true'],             'class': 'logging.StreamHandler',         }     },     'loggers': {         '': {             'level': 'INFO',             'handlers': ['console'],         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043c\u044b \u0432\u043d\u0435\u0441\u043b\u0438:<\/p>\n<ul>\n<li>\n<p>\u0427\u0442\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u041e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0434\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 docker-compose \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 production \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0435 \u0437\u0430\u0434\u0430\u043d\u044b (\u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u043e\u0442\u043b\u0430\u0434\u043a\u0438);<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0435\u043a\u0446\u0438\u044e INSTALLED_APPS \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 rest_framework \u0438 students;<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043c\u0435\u043d\u044f\u043b\u0438 STATIC_URL \u0438 STATIC_ROOT \u043d\u0430 django_static, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043a\u043e\u043b\u043b\u0438\u0437\u0438\u0438 \u0441 React \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0441\u0435\u043a\u0446\u0438\u044e MEDIA_URL \u0438 MEDIA_ROOT \u0434\u043b\u044f \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u0435\u0434\u0438\u0430-\u0441\u0442\u0430\u0442\u0438\u043a\u0438 (\u0430\u0432\u0430\u0442\u0430\u0440\u043e\u043a) \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u043e\u0442\u043b\u0430\u0434\u043a\u0438. \u0412 \u0440\u0435\u0436\u0438\u043c\u0435 production \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 Nginx;<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0441\u0435\u043a\u0446\u0438\u044e LOGGING.<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043d\u0430\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0444\u0430\u0439\u043b <code>\/demo\/django_project\/requirements.txt<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 21 &#8212; \/demo\/django_project\/requirements.txt<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>Django==4.2.4 djangorestframework==3.14.0 pika==1.3.2 psycopg2-binary==2.9.7 Pillow==10.0.0<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0438\u0445:<\/p>\n<pre><code class=\"bash\">pip install -r requirements.txt<\/code><\/pre>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u0441\u0440\u0430\u0437\u0443 \u0441\u043e\u0431\u0435\u0440\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0434\u043b\u044f Django \u0430\u0434\u043c\u0438\u043d\u043a\u0438. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u043b\u0438\u0448\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0438 \u0432 \u043e\u0431\u0445\u043e\u0434 nginx, \u0442\u043e \u044d\u0442\u043e\u0442 \u0448\u0430\u0433 \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f. \u041d\u043e \u043e\u043d \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 (\u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0432\u043a\u043b\u044e\u0447\u0430\u044f Django, React \u0438 Node.js).<\/p>\n<pre><code class=\"bash\">python manage.py collectstatic<\/code><\/pre>\n<p>\u041c\u044b \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0433\u043e\u0442\u043e\u0432\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430\u0448 Django-\u0441\u0435\u0440\u0432\u0435\u0440. \u041d\u043e \u0441\u043f\u0435\u0440\u0432\u0430 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c RabbitMQ, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442 \u043e\u0431\u043c\u0435\u043d \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c Django-\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0438 Worker-\u043e\u043c. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u044b\u0437\u043e\u0432\u0430 docker-compose \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 <code>\/demo<\/code>. \u041f\u043e\u043f\u0443\u0442\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0431\u0440\u0430\u043d \u0438 \u0437\u0430\u043f\u0443\u0449\u0435\u043d Nginx, \u0445\u043e\u0442\u044f \u043e\u043d \u043d\u0430\u043c \u043f\u043e\u043a\u0430 \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f.<\/p>\n<pre><code class=\"bash\">docker-compose -f dev.docker-compose.yml build docker-compose -f dev.docker-compose.yml up -d<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c Django \u0438 Worker. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 <code>\/demo\/start.sh<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 22 &#8212; \/demo\/start.sh<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">run_cmd=\"cd django_project &amp;&amp; python -u manage.py runserver 0.0.0.0:8000  > ..\/log_server.log 2>&amp;1\" run_cmd+=\"&amp; cd django_project &amp;&amp; python -u manage.py worker > ..\/log_worker.log 2>&amp;1\" nohup sh -c \"$run_cmd\" &amp;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"bash\">chmod 700 \/demo\/start.sh<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c Django \u0438 Worker \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u043b\u043e\u0433\u0438 \u0432 log_server.log \u0438 log_worker.log, \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>tail -f log_server.log<\/code>.<\/p>\n<p>\u0421\u0434\u0435\u043b\u0430\u0435\u043c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 <code>\/demo\/stop.sh<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 23 &#8212;  \/demo\/stop.sh<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">pkill -f \"python -u manag[e].py\"<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0430\u0434\u043c\u0438\u043d\u043a\u0435 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 (\u0432 \u043f\u0430\u043f\u043a\u0435 <code>demo\/django_project\/<\/code>)<\/p>\n<pre><code class=\"python\">python manage.py createsuperuser<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c Django \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>.\/start.sh<\/code> \u0438 \u0437\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 127.0.0.1:8000\/admin, \u043b\u043e\u0433\u0438\u043d\u0438\u043c\u0441\u044f \u0438 \u0432\u0438\u0434\u0438\u043c \u043f\u0430\u043d\u0435\u043b\u044c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430. \u0417\u0434\u0435\u0441\u044c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c18\/bbe\/3e9\/c18bbe3e989cf890856d7ec60661e44e.png\" alt=\"\u041b\u043e\u0433\u0438 \u043e\u043a\u043d\u043e Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0438\" title=\"\u041b\u043e\u0433\u0438 \u043e\u043a\u043d\u043e Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0438\" width=\"395\" height=\"293\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c18\/bbe\/3e9\/c18bbe3e989cf890856d7ec60661e44e.png\"\/><\/p>\n<div><figcaption>\u041b\u043e\u0433\u0438 \u043e\u043a\u043d\u043e Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0438<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/618\/866\/129\/618866129b42392a82b5f1f6e1a0bc8f.png\" alt=\"Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0430\" title=\"Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0430\" width=\"923\" height=\"313\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/618\/866\/129\/618866129b42392a82b5f1f6e1a0bc8f.png\"\/><\/p>\n<div><figcaption>Django-\u0430\u0434\u043c\u0438\u043d\u043a\u0430<\/figcaption><\/div>\n<\/figure>\n<h2>React \u043f\u0440\u043e\u0435\u043a\u0442<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a React-\u043f\u0440\u043e\u0435\u043a\u0442\u0443. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 URL \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/reactapp\/src\/index.js<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 24 &#8212; \/demo\/reactapp\/src\/index.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import React from 'react'; import ReactDOM from 'react-dom\/client'; import '.\/index.css'; import App from '.\/components\/App'; import reportWebVitals from '.\/reportWebVitals'; import 'bootstrap\/dist\/css\/bootstrap.min.css' import axios from \"axios\";  export const API_URL = \"\/api\"; export const API_STATIC_MEDIA = \"\"; export const WS_URL = window.location.href.replace('http:\/\/', 'ws:\/\/').replace('https:\/\/', 'wss:\/\/') + 'ws';  axios.defaults.xsrfCookieName = 'csrftoken' axios.defaults.xsrfHeaderName = \"X-CSRFToken\"  const root = ReactDOM.createRoot(document.getElementById('root')); root.render(   &lt;React.StrictMode>     &lt;App \/>   &lt;\/React.StrictMode> );  reportWebVitals();<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0436\u0435, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b <code>\/demo\/reactapp\/src\/utils.js<\/code> \u0434\u043b\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 (\u043f\u0430\u0440\u0441\u0438\u043d\u0433 Cookie).<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 25 &#8212; \/demo\/reactapp\/src\/utils.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">const getCookie = function(name) {   const value = `; ${document.cookie}`;   const parts = value.split(`; ${name}=`);   if (parts.length === 2) return parts.pop().split(';').shift(); }  export default getCookie;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b xsrfCookieName \u0438 xsrfHeaderName \u2013 \u044d\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 CSRF-\u0442\u043e\u043a\u0435\u043d\u0430 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u043a Django.<\/p>\n<p>\u0423\u0434\u0430\u043b\u0438\u043c \u0444\u0430\u0439\u043b <code>\/demo\/reactapp\/src\/App.js<\/code><\/p>\n<pre><code class=\"bash\">rm src\/App.js<\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0444\u0430\u0439\u043b <code>\/demo\/reactapp\/src\/components\/App.css<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 26 &#8212; \/demo\/reactapp\/src\/components\/App.css<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"css\">.App {   text-align: center; }  .App-logo {   height: 40vmin;   pointer-events: none; }  @media (prefers-reduced-motion: no-preference) {   .App-logo {     animation: App-logo-spin infinite 20s linear;   } }  .App-header {   background-color: #282c34;   min-height: 100vh;   display: flex;   flex-direction: column;   align-items: center;   justify-content: center;   font-size: calc(10px + 2vmin);   color: white; }  .App-link {   color: #61dafb; }  @keyframes App-logo-spin {   from {     transform: rotate(0deg);   }   to {     transform: rotate(360deg);   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>\/demo\/reactapp\/src\/components\/App.js<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 27 &#8212; \/demo\/reactapp\/src\/components\/App.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import { Fragment, useState, useEffect } from 'react'; import '.\/App.css'; import Header from \".\/Header\"; import Home from \".\/Home\"; import Login from \".\/Login\"; import ToastMsg from \".\/ToastMsg\"; import useWebSocket from 'react-use-websocket'; import {API_URL, WS_URL} from \"..\/index.js\"; import axios from \"axios\"; import getCookie from \"..\/utils.js\";  function App() {   const [loading, setLoading] = useState()   const [isLoggedIn, setIsLoggedIn] = useState(true)   const [formUsername, setFormUsername] = useState()   const [formPassword, setFormPassword] = useState()   const [ students, setStudents] = useState([])   const [ error, setError] = useState()   const [showToast, setShowToast] = useState(false)   const [toastMsg, setToastMsg] = useState(\"\")   const csrftoken = getCookie('csrftoken')   const [socketUrl, setSocketUrl] = useState(null);    useEffect(() => {     if (isLoggedIn) {         fetch(API_URL + \"\/students\/\", {headers: {'Content-Type': 'application\/json;charset=utf-8'}})           .then(response => {             if (response.ok) {               return response.json()             } else if (response.status === 403) {               throw Error(\"Access denied\")             } else {               throw Error(`Something went wrong: code ${response.status}`)             }           }).then(responseData => {             setStudents(responseData)           })           .catch(error => {             console.log(error)             if (error.message !== \"Access denied\") setError('\u041e\u0448\u0438\u0431\u043a\u0430, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438')             setIsLoggedIn(false)           })     }   }, [isLoggedIn])    const submitHandler = e => {     e.preventDefault();     setLoading(true);     fetch(       API_URL + \"\/login\",       {         method: 'POST',         headers: {           'Content-Type': 'application\/json;charset=utf-8',           'X-CSRFToken': csrftoken,         },         body: JSON.stringify({           username: formUsername,           password: formPassword,         })       }     )       .then(response => {         if (response.ok) {           return response.json()         } else {           throw Error(`Something went wrong: code ${response.status}`)         }       })       .then(({key}) => {           setIsLoggedIn(true)           setError(null)           setToastMsg(\"Successfully logged in\")           setShowToast(true)           setSocketUrl(WS_URL)       })       .catch(error => {         console.log(error)         setToastMsg(\"Network error. Check console\")         setShowToast(true)       })       .finally(setLoading(false))     }    const resetState = () => {       axios.get(API_URL + \"\/students\/\").then(data => setStudents(data.data))   };    useWebSocket(socketUrl, {     onOpen: () => {       console.log('WebSocket connection established.');     },     onMessage: (e) => {       const msg = JSON.parse(e.data);       if (msg[\"type\"] === 'refresh') {           setToastMsg(\"Refreshing list\")           setShowToast(true)           resetState();       }     }   });    useEffect(() => {     if (isLoggedIn) {         setSocketUrl(WS_URL);     } else {         setSocketUrl(null);     }   }, [isLoggedIn]);    return (     &lt;Fragment>       &lt;Header isLoggedIn={isLoggedIn} setIsLoggedIn={setIsLoggedIn}\/>         &lt;ToastMsg show={showToast} setShow={setShowToast} msg={toastMsg}\/>         {error? &lt;p>{error}&lt;\/p> : null}         {isLoggedIn?             error?                 null             :                 &lt;div>                     &lt;Home students={students} setStudents={setStudents} resetState={resetState}\/>                 &lt;\/div>           :             loading? \"\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430...\" :             &lt;Login onSubmit={submitHandler} setFormUsername={setFormUsername} setFormPassword={setFormPassword}\/>         }     &lt;\/Fragment>   );  }  export default App;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0444\u043b\u0430\u0433 isLoggedIn, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 True. \u0422.\u0435. \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 URL \/api\/students \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u043e\u0448\u0438\u0431\u043a\u0443, \u0442\u043e\u0433\u0434\u0430 \u0444\u043b\u0430\u0433 isLoggedIn \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0432 False. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0434\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Login. \u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 submitHandler \u0447\u0435\u0440\u0435\u0437 props \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 onSubmit. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0432\u0432\u043e\u0434\u0435 \u043b\u043e\u0433\u0438\u043d\u0430 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0432\u044b\u0437\u043e\u0432 SubmitHandler, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043f\u043e\u0441\u0442\u0443\u0447\u0438\u0442\u0441\u044f \u043d\u0430 \/api\/login \u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 Cookie \u0441 SessionToken-\u043e\u043c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u0442 \u043d\u0430\u0441 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438\u0446\u0435\u043f\u043b\u044f\u0442\u044c \u0435\u0433\u043e \u043a\u043e \u0432\u0441\u0435\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 isLoggedIn \u043d\u0430 True \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0445\u0443\u043a useEffect, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 WS_URL \u0441 null \u043d\u0430 URL-\u0441\u043e\u043a\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Node.js. \u042d\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043f\u043e \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u0445\u0443\u043a useWebSocket, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u043d\u0430\u0447\u043d\u0435\u0442 \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0412 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0432 \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d Cookie \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c \u0441\u0435\u0441\u0441\u0438\u0438, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448 \u0441\u043e\u043a\u0435\u0442-\u043a\u043b\u0438\u0435\u043d\u0442. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u044d\u0442\u043e\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0431\u044b\u043b \u043e\u043f\u0438\u0441\u0430\u043d \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 (\u0441\u043c. \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e auth_request).<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0436\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0436\u0435 \u0437\u0430\u043b\u043e\u0433\u0438\u043d\u0438\u043b\u0441\u044f, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Home \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u0438 Toast \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 ToastMsg, \u0441\u043e\u043e\u0431\u0449\u0430\u044e\u0449\u0435\u0435 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u0432\u0445\u043e\u0434\u0435.<\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043e\u0431\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0430 \u043d\u0430 \u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0430\u0445 \u043d\u0438\u0436\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/915\/081\/1f2\/9150811f2e07111acf6ee40fc8276b97.png\" width=\"1585\" height=\"882\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/915\/081\/1f2\/9150811f2e07111acf6ee40fc8276b97.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1c9\/6f4\/9f3\/1c96f49f3889cb91d17e54b2309bb027.png\" width=\"1619\" height=\"970\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1c9\/6f4\/9f3\/1c96f49f3889cb91d17e54b2309bb027.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/41f\/2e2\/40b\/41f2e240b603825bfcbfdd4c250698b7.png\" width=\"1629\" height=\"954\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/41f\/2e2\/40b\/41f2e240b603825bfcbfdd4c250698b7.png\"\/><\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>\/demo\/reactapp\/src\/components\/Login.js<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 28 &#8212; \/demo\/reactapp\/src\/components\/Login.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {   Container, Row, Col, Card, CardBody, Button,   Form, FormGroup, Label, Input } from \"reactstrap\";  const Login = (props) => {   let loginHandler = props.onSubmit;   let setUsername = props.setFormUsername;   let setPassword = props.setFormPassword;    return (     &lt;Container style={{'maxWidth':500, 'padding': 20}}>       &lt;Row>         &lt;Col>           &lt;Card>             &lt;CardBody>               &lt;Form onSubmit={loginHandler}>                 &lt;FormGroup className=\"pb-2 mr-sm-2 mb-sm-0\">                   &lt;Label for=\"exampleUsername\" className=\"mr-sm-2\"> Username &lt;\/Label>                   &lt;Input type=\"text\" name=\"email\" id=\"exampleUsername\"                     onChange={(ev) => setUsername(ev.currentTarget.value)}                   \/>                 &lt;\/FormGroup>                 &lt;FormGroup className=\"pb-2 mr-sm-2 mb-sm-0\">                   &lt;Label for=\"examplePassword\" className=\"mr-sm-2\"> Password &lt;\/Label>                   &lt;Input type=\"password\" name=\"password\" id=\"examplePassword\"                     onChange={(ev) => setPassword(ev.currentTarget.value)}                   \/>                 &lt;\/FormGroup>                 &lt;Button type=\"submit\" color=\"primary\">                   Login                 &lt;\/Button>               &lt;\/Form>             &lt;\/CardBody>           &lt;\/Card>         &lt;\/Col>       &lt;\/Row>     &lt;\/Container>   ); };  export default Login;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 <code>\/demo\/reactapp\/src\/components\/Home.js<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 29 &#8212; \/demo\/reactapp\/src\/components\/Home.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {Container, Row, Col} from \"reactstrap\"; import ListStudents from \".\/ListStudents\"; import ModalStudent from \".\/ModalStudent\";  const Home = (props) => {     let students = props.students;     let resetState = props.resetState;      return (         &lt;Container style={{marginTop: \"20px\"}}>             &lt;Row>                 &lt;Col>                     &lt;ListStudents students={students} resetState={resetState} newStudent={false}\/>                 &lt;\/Col>             &lt;\/Row>             &lt;Row>                 &lt;Col>                     &lt;ModalStudent                     create={true}                     resetState={resetState}                     newStudent={true}\/>                 &lt;\/Col>             &lt;\/Row>         &lt;\/Container>     ) }  export default Home;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 30 &#8212; \/demo\/reactapp\/src\/components\/Header.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import axios from \"axios\"; import { Navbar, NavbarBrand, Nav, Button } from 'reactstrap'; import {API_URL} from \"..\/index.js\";  function Header (props) {     let isLoggedIn = props.isLoggedIn;     let setIsLoggedIn = props.setIsLoggedIn;      const handleLogout = e => {         axios.post(API_URL + \"\/logout\",)         localStorage.clear();         window.location.href = '\/';         setIsLoggedIn(false);     }      return (       &lt;div>         &lt;Navbar color=\"light\" light expand=\"md\">           &lt;NavbarBrand className='m-auto'>Students demo&lt;\/NavbarBrand>             &lt;Nav navbar>               {isLoggedIn? &lt;Button onClick={handleLogout}>Logout&lt;\/Button> : null}             &lt;\/Nav>         &lt;\/Navbar>       &lt;\/div>     ); }  export default Header;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 31 &#8212; \/demo\/reactapp\/src\/components\/ListStudents.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {Table} from \"reactstrap\"; import ModalStudent from \".\/ModalStudent\"; import AppRemoveStudent from \".\/appRemoveStudent\"; import ModalPhoto from \".\/ModalPhoto\";  const ListStudents = (props) => {     const {students} = props     return (         &lt;Table>             &lt;thead>             &lt;tr>                 &lt;th>Name&lt;\/th>                 &lt;th>Email&lt;\/th>                 &lt;th>Document&lt;\/th>                 &lt;th>Phone&lt;\/th>                 &lt;th>Registration&lt;\/th>                 &lt;th>Photo&lt;\/th>                 &lt;th>&lt;\/th>             &lt;\/tr>             &lt;\/thead>             &lt;tbody>             {!students || students.length &lt;= 0 ? (                 &lt;tr>                     &lt;td colSpan=\"6\" align=\"center\">                         &lt;b>\u041f\u043e\u043a\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442&lt;\/b>                     &lt;\/td>                 &lt;\/tr>             ) : students.map(student => (                     &lt;tr key={student.pk}>                         &lt;td>{student.name}&lt;\/td>                         &lt;td>{student.email}&lt;\/td>                         &lt;td>{student.document}&lt;\/td>                         &lt;td>{student.phone}&lt;\/td>                         &lt;td>{student.registrationDate}&lt;\/td>                         &lt;td>&lt;ModalPhoto                             student={student}                         \/>&lt;\/td>                         &lt;td>                             &lt;ModalStudent                                 create={false}                                 student={student}                                 resetState={props.resetState}                                 newStudent={props.newStudent}                             \/>                             &amp;nbsp;&amp;nbsp;                             &lt;AppRemoveStudent                                 pk={student.pk}                                 resetState={props.resetState}                             \/>                         &lt;\/td>                     &lt;\/tr>                 )             )}             &lt;\/tbody>         &lt;\/Table>     ) }  export default ListStudents<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 32 &#8212; \/demo\/reactapp\/src\/components\/ModalStudent.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {Fragment, useState} from \"react\"; import {Button, Modal, ModalHeader, ModalBody} from \"reactstrap\"; import StudentForm from \".\/StudentForm\";  const ModalStudent = (props) => {     const [visible, setVisible] = useState(false)     var button = &lt;Button onClick={() => toggle()}>\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c&lt;\/Button>;      const toggle = () => {         setVisible(!visible)     }      if (props.create) {         button = (             &lt;Button                 color=\"primary\"                 className=\"float-right\"                 onClick={() => toggle()}                 style={{minWidth: \"200px\"}}>                 Add student             &lt;\/Button>         )     }     return (         &lt;Fragment>             {button}             &lt;Modal isOpen={visible} toggle={toggle}>                 &lt;ModalHeader                     style={{justifyContent: \"center\"}}>{props.create ? \"Add student\" : \"Edit student\"}&lt;\/ModalHeader>                 &lt;ModalBody>                     &lt;StudentForm                         student={props.student ? props.student : []}                         resetState={props.resetState}                         toggle={toggle}                         newStudent={props.newStudent}                     \/>                 &lt;\/ModalBody>             &lt;\/Modal>         &lt;\/Fragment>     ) } export default ModalStudent;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 33 &#8212; \/demo\/reactapp\/src\/components\/ModalPhoto.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {useState} from \"react\"; import {API_STATIC_MEDIA} from \"..\/index\"; import {Button, Modal, ModalBody, ModalFooter, ModalHeader} from \"reactstrap\";  const ModalPhoto = (props) => {     const [visible, setVisible] = useState(false)     const toggle = () => {         setVisible(!visible)     }     return (         &lt;>             &lt;img onClick={toggle} src={API_STATIC_MEDIA + props.student.photo} alt='loading' style={{height: 50}}\/>             &lt;Modal isOpen={visible} toggle={toggle}>                 &lt;ModalHeader  style={{color:\"white\",justifyContent: \"center\", backgroundColor:\"#212529\"}}>\u0424\u043e\u0442\u043e&lt;\/ModalHeader>                 &lt;ModalBody style={{display:\"flex\", justifyContent:\"center\", backgroundColor:\"#212529\"}}>&lt;img src={API_STATIC_MEDIA + props.student.photo} alt=\"loading\"\/>&lt;\/ModalBody>                 &lt;ModalFooter style={{display:\"flex\", justifyContent:\"center\", backgroundColor:\"#212529\"}}> &lt;Button type=\"button\" onClick={() => toggle()}>\u0417\u0430\u043a\u0440\u044b\u0442\u044c&lt;\/Button>&lt;\/ModalFooter>             &lt;\/Modal>         &lt;\/>     ) }  export default ModalPhoto;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 34 &#8212; \/demo\/reactapp\/src\/components\/appRemoveStudent.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {Fragment, useState} from \"react\"; import {Button, Modal, ModalHeader, ModalFooter} from \"reactstrap\"; import axios from \"axios\"; import {API_URL} from \"..\/index\";  const AppRemoveStudent = (props) => {     const [visible, setVisible] = useState(false)     const toggle = () => {         setVisible(!visible)     }     const deleteStudent = () => {         axios.delete(API_URL + \"\/students\/\" + props.pk).then(() => {             props.resetState()             toggle();         });     }     return (         &lt;Fragment>             &lt;Button color=\"danger\" onClick={() => toggle()}>                 Delete             &lt;\/Button>             &lt;Modal isOpen={visible} toggle={toggle} style={{width: \"300px\"}}>                 &lt;ModalHeader style={{justifyContent: \"center\"}}>\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b?&lt;\/ModalHeader>                 &lt;ModalFooter style={{display: \"flex\", justifyContent: \"space-between\"}}>                     &lt;Button                         type=\"button\"                         onClick={() => deleteStudent()}                         color=\"primary\"                     >\u0423\u0434\u0430\u043b\u0438\u0442\u044c&lt;\/Button>                     &lt;Button type=\"button\" onClick={() => toggle()}>\u041e\u0442\u043c\u0435\u043d\u0430&lt;\/Button>                 &lt;\/ModalFooter>             &lt;\/Modal>         &lt;\/Fragment>     ) } export default AppRemoveStudent;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 35 &#8212; \/demo\/reactapp\/src\/components\/StudentForm.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import {useEffect, useState} from \"react\"; import {Button, Form, FormGroup, Input, Label} from \"reactstrap\"; import axios from \"axios\"; import {API_URL} from \"..\/index\";  const StudentForm = (props) => {     const [student, setStudent] = useState({})      const onChange = (e) => {         const newState = student         if (e.target.name === \"file\") {             newState[e.target.name] = e.target.files[0]         } else newState[e.target.name] = e.target.value         setStudent(newState)     }      useEffect(() => {         if (!props.newStudent) {             setStudent(student => props.student)         }         \/\/ eslint-disable-next-line     }, [props.student])      const defaultIfEmpty = value => {         return value === \"\" ? \"\" : value;     }      const submitDataEdit = async (e) => {         e.preventDefault();         \/\/ eslint-disable-next-line         const result = await axios.put(API_URL + \"\/students\/\" + student.pk, student, {headers: {'Content-Type': 'multipart\/form-data'}})             .then(() => {                 props.resetState()                 props.toggle()             })     }     const submitDataAdd = async (e) => {         e.preventDefault();         const data = {             name: student['name'],             email: student['email'],             document: student['document'],             phone: student['phone'],             photo: \"\/\",             file: student['file']         }         \/\/ eslint-disable-next-line         const result = await axios.post(API_URL + \"\/students\/\", data, {headers: {'Content-Type': 'multipart\/form-data'}})             .then(() => {                 props.resetState()                 props.toggle()             })     }     return (         &lt;Form onSubmit={props.newStudent ? submitDataAdd : submitDataEdit}>             &lt;FormGroup>                 &lt;Label for=\"name\">Name:&lt;\/Label>                 &lt;Input                     type=\"text\"                     name=\"name\"                     onChange={onChange}                     defaultValue={defaultIfEmpty(student.name)}                 \/>             &lt;\/FormGroup>             &lt;FormGroup>                 &lt;Label for=\"email\">Email&lt;\/Label>                 &lt;Input                     type=\"email\"                     name=\"email\"                     onChange={onChange}                     defaultValue={defaultIfEmpty(student.email)}                 \/>             &lt;\/FormGroup>             &lt;FormGroup>                 &lt;Label for=\"document\">Document:&lt;\/Label>                 &lt;Input                     type=\"text\"                     name=\"document\"                     onChange={onChange}                     defaultValue={defaultIfEmpty(student.document)}                 \/>             &lt;\/FormGroup>             &lt;FormGroup>                 &lt;Label for=\"phone\">Phone:&lt;\/Label>                 &lt;Input                     type=\"text\"                     name=\"phone\"                     onChange={onChange}                     defaultValue={defaultIfEmpty(student.phone)}                 \/>             &lt;\/FormGroup>             &lt;FormGroup>                 &lt;Label for=\"photo\">Photo:&lt;\/Label>                 &lt;Input                     type=\"file\"                     name=\"file\"                     onChange={onChange}                     accept='image\/*'                 \/>             &lt;\/FormGroup>             &lt;div style={{display: \"flex\", justifyContent: \"space-between\"}}>                 &lt;Button>Send&lt;\/Button> &lt;Button onClick={props.toggle}>Cancel&lt;\/Button>             &lt;\/div>         &lt;\/Form>     ) }  export default StudentForm;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 36 &#8212; \/demo\/reactapp\/src\/components\/ToastMsg.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">import Row from 'react-bootstrap\/Row'; import Toast from 'react-bootstrap\/Toast'; import ToastContainer from 'react-bootstrap\/ToastContainer';  function ToastMsg(props) {   const show = props.show;   const setShow = props.setShow;   const msg = props.msg;    return (     &lt;Row>       &lt;ToastContainer position='top-center'>         &lt;Toast onClose={() => setShow(false)} show={show} delay={3000} autohide>           &lt;Toast.Header>             &lt;img               src=\"holder.js\/20x20?text=%20\"               className=\"rounded me-2\"               alt=\"\"             \/>             &lt;strong className=\"me-auto\">Notification&lt;\/strong>           &lt;\/Toast.Header>           &lt;Toast.Body>{msg}&lt;\/Toast.Body>         &lt;\/Toast>       &lt;\/ToastContainer>     &lt;\/Row>   ); }  export default ToastMsg;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u0444\u0430\u0439\u043b <code>\/demo\/reactapp\/package.json<\/code> (\u0432 \u0441\u0435\u043a\u0446\u0438\u044e dependencies)<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 37 &#8212; \/demo\/reactapp\/package.json (\u0441\u0435\u043a\u0446\u0438\u044f dependencies)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">\"dependencies\": {     \"axios\": \"^1.5.0\",     \"bootstrap\": \"^5.3.2\",     \"react-bootstrap\": \"^2.8.0\",     \"react-use-websocket\": \"^4.4.0\",     \"reactstrap\": \"^9.2.0\",     \"amqplib\": \"^0.10.3\", }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0438\u0445 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0440\u0435\u0436\u0438\u043c\u0430 \u043e\u0442\u043b\u0430\u0434\u043a\u0438. \u041d\u0430\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 Nginx.<\/p>\n<pre><code class=\"bash\">npm install<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442\u0430 \u043d\u0430\u043c \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e \u0432 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/reactapp\/src\/socket.js<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 38 &#8212; \/demo\/reactapp\/src\/socket.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">var amqp = require('amqplib'); var uuid = require('uuid'); var SOCKET_OPEN = 1;  const queue = \"to_socket\";  function sleep(ms) {   return new Promise((resolve) => {     setTimeout(resolve, ms);   }); }  (async () => {   var connected = false   const RMQ_HOST=process.env.RMQ_HOST || \"127.0.0.1\"   const RMQ_PORT=process.env.RMQ_PORT || 5672   const RMQ_USER=process.env.RMQ_USER || \"admin\"   const RMQ_PASS=process.env.RMQ_PASS || \"admin\"   while (!connected) {       await sleep(1000);       console.log(\"Rabbitmq connection attempt\")       try {         const connection = await amqp.connect(\"amqp:\/\/\"+RMQ_USER+\":\"+RMQ_PASS+\"@\"+RMQ_HOST+\":\"+RMQ_PORT);         const channel = await connection.createChannel();          process.once(\"SIGINT\", async () => {           await channel.close();           await connection.close();         });          await channel.assertQueue(queue, { durable: false });         await channel.consume(           queue,           (message) => {             if (message) {               console.log(\"Received refresh message\");               for (const [key, ws] of Object.entries(clients)) {                     if (ws.readyState === SOCKET_OPEN) {                       ws.send(message.content.toString());                     } else {                       delete clients[key];                     }               }             }           },           { noAck: true }         );         connected = true;         console.log(\"Connected to RabbiqMQ, waiting for messages\");       } catch (err) {         console.warn(err);       }   } })();  function getCookiesMap(cookiesString) {   return cookiesString.split(\";\")     .map(function(cookieString) {         return cookieString.trim().split(\"=\");     })     .reduce(function(acc, curr) {         acc[curr[0]] = curr[1];         return acc;     }, {}); }  console.log(\"Server started\"); var Msg = ''; var clients = {}; var WebSocketServer = require('ws').Server     , wss = new WebSocketServer({port: 8010});     wss.on('connection', function(ws, req) {         if (req.headers.cookie) {             var cookies = getCookiesMap(req.headers.cookie);             var sessionid = cookies[\"sessionid\"];             var socketid = uuid.v4();             console.log(sessionid);             clients[socketid] = ws;             console.log(\"New connection from %s\", sessionid);             ws.on('message', function(message) {               console.log('Received from client: %s', message);               ws.send('Server received from client: ' + message);             });         } else {console.log(\"New connection\");}  });<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430. \u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043e\u043d \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a RabbitMQ \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0435 to_socket. \u041e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u044b \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c clients. \u041f\u0440\u0438 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f to_socket \u0432\u0441\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u0434\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432, \u043e\u043d\u0438 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u044f\u0442\u0441\u044f \u0443 \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0415\u0441\u043b\u0438 \u0443 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043a\u043b\u0430\u0434\u043e\u043a, \u0442\u043e \u043e\u043d\u0438 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u043d\u043e\u0432\u044f\u0442\u0441\u044f.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0446\u0435\u043b\u0438\u043a\u043e\u043c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0430\u0448 \u0441\u043a\u0440\u0438\u043f\u0442 \/demo\/start.sh \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Webpack \u0438 Node.js<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 39 &#8212;  \/demo\/start.sh<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">run_cmd=\"cd django_project &amp;&amp; python -u manage.py runserver 0.0.0.0:8000 > ..\/log_server.log 2>&amp;1\" run_cmd+=\"&amp; cd django_project &amp;&amp; python -u manage.py worker > ..\/log_worker.log 2>&amp;1\" run_cmd+=\"&amp; cd reactapp &amp;&amp; node socket.js > ..\/log_socket.log 2>&amp;1\" run_cmd+=\"&amp; cd reactapp &amp;&amp; npm run start > ..\/log_react.log 2>&amp;1\" nohup sh -c \"$run_cmd\" &amp;<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0441\u0440\u0430\u0437\u0443 <code>stop.sh<\/code> \u0434\u043b\u044f \u0438\u0445 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 40 &#8212; \/demo\/stop.sh<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">pkill -f \"node.*react-scripts start\" pkill -f \"node socket.js\" pkill -f \"node.*start.js\" pkill -f \"python -u manag[e].py\"<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 \/demo\/reactapp\/package.json \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043f\u0440\u0430\u0432\u043a\u0443 (BROWSER=none), \u0447\u0442\u043e\u0431\u044b webpack \u043d\u0435 \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435. \u042d\u0442\u043e \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 &#8212; http:\/\/127.0.0.1, \u0430 \u043d\u0435 127.0.0.1:3000, \u043a\u0443\u0434\u0430 webpack \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0441 \u043f\u0435\u0440\u0435\u0431\u0440\u043e\u0441\u0438\u0442\u044c.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 41 &#8212; \/demo\/reactapp\/package.json (\u0441\u0442\u0440\u043e\u0447\u043a\u0430 start)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">  \"scripts\": {     \"start\": \"BROWSER=none react-scripts start\",     \"build\": \"react-scripts build\",     \"test\": \"react-scripts test\",     \"eject\": \"react-scripts eject\" },<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>start.sh<\/code>. \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c <code>stop.sh<\/code> \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c nginx, \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0443\u0436\u0435 \u0447\u0442\u043e-\u0442\u043e \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0448\u0430\u0433\u043e\u0432.<\/p>\n<pre><code class=\"bash\">docker-compose -f dev.docker-compose.yml restart nginx .\/start.sh<\/code><\/pre>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 http:\/\/127.0.0.1 \u0438 \u043f\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441 \u0432 \u0441\u0431\u043e\u0440\u043a\u0435.<\/p>\n<h2>Production-\u0440\u0435\u0436\u0438\u043c<\/h2>\n<p>\u041a\u0430\u043a \u043c\u044b \u0438 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0435 \u043f\u0430\u0440\u0443 Dockerfile-\u043e\u0432:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 42 &#8212; \/demo\/Dockerfile.django<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">FROM python:3.11-alpine  WORKDIR \/usr\/src\/app RUN mkdir -p $WORKDIR\/static RUN mkdir -p $WORKDIR\/media  ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1  RUN apk update \\     &amp;&amp; apk add postgresql-dev gcc python3-dev musl-dev  RUN pip install --upgrade pip  COPY .\/django_project\/requirements.txt . RUN pip install -r requirements.txt  COPY .\/django_project .  ENTRYPOINT [\"\/usr\/src\/app\/entrypoint.sh\" ]<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u0438\u0434\u0435\u0442 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u0432\u044b\u0437\u043e\u0432 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 <code>entrypoint.sh<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 43 &#8212; \/demo\/django_project\/entrypoint.sh<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">#!\/bin\/sh  until cd \/usr\/src\/app\/ do     echo \"Waiting for server volume...\" done  if [ \"$DATABASE\" = \"postgres\" ] then     while ! nc -z $POSTGRES_HOST $POSTGRES_PORT; do       echo \"Waiting for db to be ready...\"       sleep 0.1     done fi  python manage.py migrate  .\/manage.py collectstatic --noinput .\/manage.py loaddata fixtures\/students.json --app students  nohup python manage.py worker &amp; python manage.py runserver 0.0.0.0:8000 <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u0442\u043e\u0442 \u0441\u043a\u0440\u0438\u043f\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 Django, \u0434\u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f Volume, \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0411\u0414, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043f\u0440\u043e\u0433\u043e\u043d \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 (\u0435\u0441\u043b\u0438 \u0438\u0445 \u043d\u0435\u0442, \u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439), \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 Django \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0430\u0434\u043c\u0438\u043d\u043a\u0438 (\u043d\u0430\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u0441\u0442\u0430\u0442\u0438\u043a\u0430 React-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 Nginx), \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u0441\u043e \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430\u043c\u0438 (\u0435\u0441\u043b\u0438 \u0438\u0445 \u043d\u0435\u0442) \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 Django-\u0441\u0435\u0440\u0432\u0435\u0440 \u0441 Worker-\u043e\u043c.<\/p>\n<p>\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0430 \u043d\u0430 \u0437\u0430\u043f\u0443\u0441\u043a \u0441\u043a\u0440\u0438\u043f\u0442\u0430.<\/p>\n<pre><code class=\"bash\">chmod 700 django_project\/entrypoint.sh<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 44 &#8212; \/demo\/Dockerfile.socket<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">FROM node:18-alpine WORKDIR \/usr\/src\/app ADD .\/reactapp\/*.json .\/ ADD .\/reactapp\/socket.js .\/ RUN npm install CMD node socket.js<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<p>\u0421\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c production-\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f Nginx.<br \/> <code>\/demo\/web-demo\/nginx\/production\/nginx.conf<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 45 &#8212; \/demo\/web-demo\/nginx\/production\/nginx.conf<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"nginx\">server {     listen 80;     server_name _;     server_tokens off;     client_max_body_size 20M;      location \/ {         root   \/usr\/share\/nginx\/html;         index  index.html index.htm;         try_files $uri $uri\/ \/index.html;     }      location \/ws {         auth_request \/auth;         proxy_pass http:\/\/socket:8010;         proxy_http_version 1.1;         proxy_set_header Upgrade $http_upgrade;                 proxy_set_header Connection \"upgrade\";     }      location \/auth {         proxy_set_header Content-Type 'application\/json;charset=utf-8';         proxy_pass http:\/\/django:8000\/api\/students\/;     }      location \/api {         try_files $uri @proxy_api;     }     location \/admin {         try_files $uri @proxy_api;     }      location \/media {         autoindex on;         alias \/app\/backend\/server\/media\/;     }      location @proxy_api {         proxy_set_header X-Forwarded-Proto https;         proxy_set_header X-Url-Scheme $scheme;         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;         proxy_set_header Host $http_host;         proxy_redirect off;         proxy_pass   http:\/\/django:8000;     }      location \/django_static\/ {         autoindex on;         alias \/app\/backend\/server\/django_static\/;     }  } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u044f \u043e\u0442 \u0440\u0435\u0436\u0438\u043c\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043f\u043e \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c\u0443 URL (<code>\/<\/code>) \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f React-\u0441\u0442\u0430\u0442\u0438\u043a\u0430 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0430\u044f \u0432 bundle (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Webpack) \u0438 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0432 Nginx-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0435\u0433\u043e \u0441\u0431\u043e\u0440\u043a\u0438. \u0412\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0441 \u0442\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c, \u0447\u0442\u043e endpoint-\u044b \u0432\u0435\u0434\u0443\u0442 \u043d\u0435 \u043d\u0430 \u0445\u043e\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b, \u0430 \u043d\u0430 hostname \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0438\u043c Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 (\u0441\u043c. django:8000, socket:8010).<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c Compose-\u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 production.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 46 &#8212; \/demo\/docker-compose.yml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"yaml\">version: '2'  services:     nginx:          restart: unless-stopped         container_name: demo_nginx         build:             context: .             dockerfile: .\/Dockerfile.nginx         ports:             - 80:80         volumes:             - static_volume:\/app\/backend\/server\/django_static             - media_volume:\/app\/backend\/server\/media             - .\/nginx\/production:\/etc\/nginx\/conf.d         depends_on:              - django      socket:         restart: unless-stopped         container_name: demo_socket         build:             context: .             dockerfile: Dockerfile.socket         depends_on:             - rmq         env_file:             - .\/.env      django:         restart: unless-stopped         container_name: demo_django         build:             context: .             dockerfile: Dockerfile.django         volumes:             - static_volume:\/usr\/src\/app\/django_static             - media_volume:\/usr\/src\/app\/media         expose:             - 8000                 depends_on:             - postgres             - rmq         env_file:             - .\/.env      rmq:         image: rabbitmq:3.10-management         restart: always         container_name: demo_rmq         environment:           - RABBITMQ_DEFAULT_USER=${RMQ_USER}           - RABBITMQ_DEFAULT_PASS=${RMQ_PASS}         volumes:           - rabbitmq_data_volume:\/var\/lib\/rabbitmq\/         ports:           - 1234:15672           - 5671-5672:5671-5672         env_file:             - .\/.env      postgres:         image: postgres:15-alpine         container_name: demo_postgres         volumes:           - postgres_volume:\/var\/lib\/postgresql\/data\/         environment:           - POSTGRES_USER=${POSTGRES_USER}           - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}           - POSTGRES_DB=${POSTGRES_DB}         env_file:             - .\/.env  volumes:     static_volume: {}     media_volume: {}     postgres_volume: {}     rabbitmq_data_volume: {}<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u043a \u0432\u0441\u0435\u0445 5-\u0442\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 Volume-\u043e\u0432. \u0414\u0432\u0430 \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0445 Docker Volume (static_volume \u0438 media_volume) \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 Django \u0438 Nginx. \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0438, \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0435 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 Django \u0431\u044b\u043b\u0438 \u0432\u0438\u0434\u043d\u044b Nginx, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 Django \u0441\u0442\u0430\u0442\u0438\u043a\u0443 \u0430\u0434\u043c\u0438\u043d\u043a\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<pre><code class=\"bash\">docker-compose build docker-compose up -d<\/code><\/pre>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u0434\u043c\u0438\u043d-\u0430\u043a\u043a\u0430\u0443\u043d\u0442, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 \u0411\u0414 Postgres \u0438 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u043d\u0435\u0435 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0435 \u0432 \u043d\u0435\u0439 \u0443\u0436\u0435 \u043d\u0435\u0442.<\/p>\n<pre><code class=\"bash\">docker exec -it demo_django \/bin\/sh python manage.py createsuperuser<\/code><\/pre>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043a\u0430\u043a \u0438 \u0440\u0430\u043d\u044c\u0448\u0435 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 http:\/\/127.0.0.1<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a0d\/f27\/27f\/a0df2727f04ebc116b877ba2c62dc2f4.png\" alt=\"\u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\" title=\"\u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\" width=\"745\" height=\"325\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a0d\/f27\/27f\/a0df2727f04ebc116b877ba2c62dc2f4.png\"\/><\/p>\n<div><figcaption>\u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/figcaption><\/div>\n<\/figure>\n<p>\u041c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u043a\u043e\u043d \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0443 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0433\u0440\u0443\u0437\u044f\u0442\u0441\u044f \u0432\u043e \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u043a\u043d\u0430\u0445. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0447\u0430\u0442\u043e\u0432, \u0438\u0433\u0440 \u0438 \u0434\u0440.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u043d\u0430\u0448 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0432\u0430\u0448\u0438\u0445 \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u0420\u0435\u043f\u043e\u0437\u0438\u0442\u0430\u0440\u0438\u0439 \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 <a href=\"https:\/\/github.com\/aboev\/web-demo\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/aboev\/web-demo<\/a><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u0432\u0430\u043c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0441\u044f \u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c\u0438 \u0437\u043d\u0430\u043d\u0438\u044f\u043c\u0438 \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e\u043c, \u0431\u0443\u0434\u0443 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0435\u043d, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435 \u0441\u0442\u0430\u0442\u044c\u044e \u0443\u0436\u0435 \u0441\u043e \u0441\u0432\u043e\u0438\u043c\u0438 \u0438\u0434\u0435\u044f\u043c\u0438 \u0438 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b<\/summary>\n<div class=\"spoiler__content\">\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/713490\/\" rel=\"noopener noreferrer nofollow\">React+Django \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c Hello World<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/512746\/\" rel=\"noopener noreferrer nofollow\">\u041a\u0430\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043d\u0430 Django \u0437\u043d\u0430\u0442\u044c \u0441\u0432\u043e\u0438\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 React \u0432 \u043b\u0438\u0446\u043e, \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/saasitive.com\/tutorial\/docker-compose-django-react-nginx-let-s-encrypt\/\" rel=\"noopener noreferrer nofollow\">Docker-Compose for Django and React with Nginx reverse-proxy and Let&#8217;s encrypt certificate<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/stackoverflow.com\/questions\/64084494\/how-to-make-websocket-authentication-with-nginx-im-using-jwt-with-auth-reque\" rel=\"noopener noreferrer nofollow\">Stack Overflow &#8212; How to make websocket authentication with Nginx.<\/a><\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<p>\u0412\u0441\u0435\u043c \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u043d\u0435\u0434\u0435\u043b\u0438 \u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \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\/761526\/\"> https:\/\/habr.com\/ru\/articles\/761526\/<\/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>\u041e\u0434\u043d\u0430\u0436\u0434\u044b \u0432 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043d\u0430 React\/Django \u044f \u043d\u0430\u0448\u0435\u043b \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u043e\u0434\u043d\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0443\u044e <a href=\"https:\/\/habr.com\/ru\/articles\/713490\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0430\u0442\u044c\u044e.<\/a> \u041e\u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043c\u043d\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439, \u0438 \u044f \u0440\u0435\u0448\u0438\u043b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u043e\u0432\u044b\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438. \u0412 \u044d\u0442\u043e\u043c \u0441\u0438\u043a\u0432\u0435\u043b\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u0432\u0435\u0431-\u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 real-time \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 \u0441\u043e\u043a\u0435\u0442\u0430\u0445, \u0443\u043b\u0443\u0447\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0443 Docker-\u0441\u0431\u043e\u0440\u043a\u0438, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439 \u043d\u0430 RabbitMQ \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0433\u043b\u0430\u0434\u0438\u043c \u043a\u043e\u0441\u043c\u0435\u0442\u0438\u043a\u0443. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b.<\/p>\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0422\u0438\u043f\u043e\u0432\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f fullstack-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0441\u0442\u0435\u0439, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438, \u0431\u0440\u043e\u043a\u0435\u0440\u044b \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439, \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0431\u043e\u0440\u043a\u0438, \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0444\u0440\u043e\u043d\u0442\u043e\u0432\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, UI-\u0432\u0438\u0434\u0436\u0435\u0442\u044b \u0438 \u043c\u043d\u043e\u0433\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0440\u043e\u0433\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u043e\u0432\u0438\u0447\u043a\u0430\u043c \u043f\u043e\u0440\u043e\u0439 \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0438 \u0438 \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0432 \u0435\u0434\u0438\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442. \u0426\u0435\u043b\u044c\u044e \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0438\u0437 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u0430\u0442\u044c \u043d\u0435\u043f\u043b\u043e\u0445\u043e\u0439 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u043e\u0439 \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.<\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0435 \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u0439\u0442\u0438 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<h2>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u043d\u0438\u044f<\/h2>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 Django, \u0444\u0440\u043e\u043d\u0442-\u044d\u043d\u0434 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 React, \u0443\u043c\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b Docker, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0441\u043d\u043e\u0432\u044b \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 Nginx. \u0422\u0430\u043a\u0436\u0435, \u0432\u0441\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u043e\u0434 \u0437\u0430\u043f\u0443\u0441\u043a \u0432 \u0441\u0440\u0435\u0434\u0435 Ubuntu 20.04. \u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0441 \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u043c\u0435\u0448\u0430\u0435\u0442 \u0432\u0430\u043c \u043f\u0440\u043e\u0439\u0442\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b, \u043d\u043e \u0432\u0441\u0435 \u0436\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u201cHello-world\u201d \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/docs.djangoproject.com\/en\/4.2\/intro\/tutorial01\/\" rel=\"noopener noreferrer nofollow\">Introduction to Django<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/react.dev\/learn\" rel=\"noopener noreferrer nofollow\">Learn React<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docker-curriculum.com\/\" rel=\"noopener noreferrer nofollow\">Introduction to Docker<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.docker.com\/blog\/how-to-use-the-official-nginx-docker-image\/\" rel=\"noopener noreferrer nofollow\">Nginx with Docker tutorial<\/a><\/p>\n<\/li>\n<\/ul>\n<h2>\u041e\u0431\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h2>\n<p>\u041d\u0430\u0448 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 Django \u0434\u043b\u044f \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0444\u0440\u043e\u043d\u0442-\u044d\u043d\u0434\u0430 \u043d\u0430 React, \u0441\u043e\u043a\u0435\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 Node.js \u0434\u043b\u044f real-time \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0445 \u0438 \u0441\u0432\u044f\u0437\u0443\u044e\u0449\u0435\u0433\u043e \u0431\u0440\u043e\u043a\u0435\u0440\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043d\u0430 RabbitMQ. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 Django Channels \u0432 ASGI-\u0440\u0435\u0436\u0438\u043c\u0435 \u0438 \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0437\u0430\u0434\u0430\u0447\u0443, \u043d\u043e \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u044b \u043e\u0431\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u043f\u043b\u044e\u0448\u0435\u043a \u0438 \u0441\u043e\u0431\u0435\u0440\u0435\u043c \u0432\u0441\u0435 \u0441\u0432\u043e\u0438\u043c\u0438 \u0440\u0443\u043a\u0430\u043c\u0438.<\/p>\n<h2>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c 3 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f, \u043e\u0442\u0440\u0430\u0436\u0430\u044e\u0449\u0438\u0445 \u0442\u0438\u043f\u043e\u0432\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<ul>\n<li>\n<p><strong>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.<\/strong> \u0414\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c <a href=\"https:\/\/www.django-rest-framework.org\/api-guide\/authentication\/#sessionauthentication\" rel=\"noopener noreferrer nofollow\">Django Session Authentication<\/a>. \u042d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0442\u043e\u043a\u0435\u043d \u0441\u0435\u0441\u0441\u0438\u0438 \u0432 \u043e\u0431\u043c\u0435\u043d \u043d\u0430 \u0441\u0432\u044f\u0437\u043a\u0443 \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c, \u0438 \u044d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u0422\u043e\u043a\u0435\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 Cookies \u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0444\u0440\u043e\u043d\u0442\u0430. \u041f\u043e\u043c\u0438\u043c\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0435\u0442\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u0447\u0442\u043e\u0431\u044b \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u0438 \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0438 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u043a\u0435\u043d\u0430-\u0441\u0435\u0441\u0441\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430<\/strong>. \u041f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430 \u0435\u0433\u043e \u0430\u0432\u0430\u0442\u0430\u0440  \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 Django. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u044b. \u042d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 Worker (\u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u043d\u044b\u0439 \u0432 \u0432\u0438\u0434\u0435 <a href=\"https:\/\/docs.djangoproject.com\/en\/4.2\/howto\/custom-management-commands\/\" rel=\"noopener noreferrer nofollow\">Django management command<\/a>), \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0441 Django. \u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0439 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u043e\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u0438\u0437 Django \u0432 Worker \u0447\u0435\u0440\u0435\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u044c RabbitMQ (\u043a\u043b\u044e\u0447 to_resize).<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0445.<\/strong> \u041f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u0430 \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0432\u0441\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0438 \u0436\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u044d\u0442\u043e \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430 Node.js, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043a\u043b\u044e\u0447\u043e\u043c to_sockets, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 \u0438\u0437 Worker-\u0430 \u0447\u0435\u0440\u0435\u0437 RabbitMQ.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u0412\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h2>\n<p>\u0422\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u2014 \u044d\u0442\u043e \u0437\u0430\u043b\u043e\u0433 \u043a\u043e\u043c\u0444\u043e\u0440\u0442\u043d\u043e\u0439 \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u043c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e\u0439 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 Django \u0438 Webpack\/React, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u043a\u0438 \u0432 \u043a\u043e\u0434\u0435 \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u0440\u0430\u0436\u0430\u043b\u0438\u0441\u044c \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043b\u044e\u0431\u044b\u0445 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 (Nginx, RabbitMQ, PostgreSQL). \u041a\u0440\u043e\u043c\u0435 \u044d\u0442\u043e\u0433\u043e, \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0435\u0441\u043b\u0438 \u0441\u0440\u0435\u0434\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0431\u044b\u043b\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e Django, Node.js \u0438 \u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0430 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445. \u0412 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0436\u0435 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u044b \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0439 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u0448\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439.<\/p>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 1 &#8212; \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e<\/strong>. \u041e\u0434\u0438\u043d \u0438\u0437 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u2014 \u044d\u0442\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0430 \u0442\u0435 endpoint-\u044b, \u0433\u0434\u0435 \u043e\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f, \u0442.\u0435. REST-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 Django-\u0441\u0435\u0440\u0432\u0435\u0440, index.html \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 Webpack-\u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u0441\u043e\u043a\u0435\u0442\u044b \u043d\u0430 \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440. \u0422\u0430\u043a\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u201c\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438\u201d \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 (Nginx). \u041d\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c CORS-\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 Header-\u044b (Allowed Hosts \u0438 \u043f\u0440.), \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u044e\u0442\u0441\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u043e\u0439 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0432 \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043c\u0443\u0442\u0430\u0446\u0438\u044e endpoint-\u043e\u0432 \u0432 React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u0444\u0440\u043e\u043d\u0442-\u044d\u043d\u0434 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u043b\u0441\u044f \u0432 production-\u0440\u0435\u0436\u0438\u043c \u0438 \u0441\u0442\u0443\u0447\u0430\u043b\u0441\u044f \u043d\u0430 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0430\u0434\u0440\u0435\u0441\u0430. \u0412\u0441\u0435 \u044d\u0442\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c, \u043d\u043e \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447\u0438\u0442 \u043d\u0430\u0448\u0435\u0439 \u0446\u0435\u043b\u0438 \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0440\u0435\u0434\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0432\u0430\u0440\u0438\u0430\u043d\u0442 1 &#8212; \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 2 (\u0447\u0435\u0440\u0435\u0437 Webpack proxy)<\/strong>. \u0411\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u043e\u0433\u043e webpack-proxy, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u043d\u0430 Webpack \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043b\u0438\u0431\u043e \u043d\u0430 REST-\u0441\u0435\u0440\u0432\u0435\u0440 Django, \u043b\u0438\u0431\u043e \u043d\u0430 \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u043b\u0438\u0431\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0438\u0437 \u0441\u0442\u0430\u0442\u0438\u043a\u0438. \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u044d\u043d\u0434\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0441\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0443 (\u0442.\u0435. \u0432\u0441\u0435 endpoint-\u044b \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438), \u043d\u043e \u043c\u043e\u0433\u0443\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043e\u043a\u0435\u0442\u043d\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f (\u0441\u043c. <a href=\"https:\/\/github.com\/facebook\/create-react-app\/issues\/5280\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0443<\/a> \u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0443). \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u043e\u0441\u0438\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u043c\u044b\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440, \u043c\u044b \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0435\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 Nginx. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0432\u0430\u0440\u0438\u0430\u043d\u0442 2 &#8212; \u0447\u0435\u0440\u0435\u0437 Webpack proxy)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 3 &#8212; \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 (\u0447\u0435\u0440\u0435\u0437 nginx)<\/strong>. \u041d\u0430\u0448\u0430 \u0441\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c Nginx \u043a\u0430\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041f\u043e\u043c\u0438\u043c\u043e \u0443\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0440\u0435\u0436\u0438\u043c\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 Nginx, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043e\u043a\u0435\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/docs.nginx.com\/nginx\/admin-guide\/security-controls\/configuring-subrequest-authentication\/\" rel=\"noopener noreferrer nofollow\">auth_request<\/a> \u0438 \u043a\u043b\u044e\u0447\u0430 \u0441\u0435\u0441\u0441\u0438\u0438. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u043e\u0442\u043b\u0430\u0434\u0438\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u043a\u0435\u0442\u043e\u0432.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0432\u0430\u0440\u0438\u0430\u043d\u0442 3 &#8212; \u0447\u0435\u0440\u0435\u0437 Nginx)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442 4 (\u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f)<\/strong>. \u0412 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 Django \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0432 production-\u0440\u0435\u0436\u0438\u043c\u0435 (DEBUG=False), \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0434\u0438\u0430-\u0441\u0442\u0430\u0442\u0438\u043a\u0438 (\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0430\u0432\u0430\u0442\u0430\u0440\u043e\u0432 \u0432 \u043f\u0430\u043f\u043a\u0435 media) \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0438 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043e\u0442\u0433\u0440\u0443\u0437\u043a\u0443 \u043c\u0435\u0434\u0438\u0430-\u0441\u0442\u0430\u0442\u0438\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 Nginx. \u0422\u0430\u043a\u0436\u0435, bundle-\u0441\u0431\u043e\u0440\u043a\u0430 React \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0433\u0440\u0443\u0436\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Nginx \u0438 \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0439 Webpack-\u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f. \u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u0431\u0443\u0434\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0442\u0438\u043f\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0411\u0414 \u0441 SQLite \u043d\u0430 Postgres, \u043d\u043e \u043e\u043d\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0443\u0436\u0435 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u0440\u0435\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f)<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 &#8212; Docker, Docker-compose, Python3.10, Pip, Django:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 1 &#8212; \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\"># Docker sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common curl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg | sudo apt-key add - sudo add-apt-repository \"deb [arch=amd64] https:\/\/download.docker.com\/linux\/ubuntu $(lsb_release -cs) stable\" sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io  # Docker-compose v1 sudo curl -L \"https:\/\/github.com\/docker\/compose\/releases\/download\/1.25.5\/docker-compose-$(uname -s)-$(uname -m)\" -o \/usr\/local\/bin\/docker-compose sudo chmod +x \/usr\/local\/bin\/docker-compose sudo ln -s \/usr\/local\/bin\/docker-compose \/usr\/bin\/docker-compose  # Python3.10 + Pip sudo apt install software-properties-common sudo add-apt-repository ppa:deadsnakes\/ppa sudo apt install python3.10 curl -sS https:\/\/bootstrap.pypa.io\/get-pip.py | python3.10  # Django pip install django==4.2.4<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a\u0436\u0435, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f node.js. \u041d\u043e \u043c\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437 \u0441\u0440\u0435\u0434\u0443 nvm, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u043d\u043e\u0434\u044b.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 2 &#8212; \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 node.js<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">curl https:\/\/raw.githubusercontent.com\/creationix\/nvm\/master\/install.sh | bash source ~\/.bashrc nvm install 18.16.0<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u043f\u0430\u043f\u043a\u0443 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u0438 \u0437\u0430\u0432\u0435\u0434\u0435\u043c \u0432 \u043d\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043d\u0430 Django \u0438 React, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u0434\u043f\u0430\u043f\u043a\u0438 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 (\u0430\u0432\u0430\u0442\u0430\u0440\u043e\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439). \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 React \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 create-react-app, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c boilerplate-\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u043a\u0430\u043a Webpack (\u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0438 \u0441\u0431\u043e\u0440\u043a\u0438 js-\u043f\u0440\u043e\u0435\u043a\u0442\u0430) \u0438 Babel (\u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043f\u0438\u043b\u044f\u0446\u0438\u0438 js-\u043a\u043e\u0434\u0430, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044e\u0449\u0435\u0439 \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c \u0441 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u043c\u0438 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432).<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 3 &#8212; \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\"># \u041f\u0430\u043f\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 mkdir demo cd demo  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 django-admin startproject django_project  # \u041f\u0430\u043f\u043a\u0438 \u0434\u043b\u044f media-\u0444\u0430\u0439\u043b\u043e\u0432 mkdir django_project\/media mkdir django_project\/media\/photo  # \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f React-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 npm install create-react-app npx create-react-app reactapp<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041c\u043e\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0441\u0440\u0430\u0437\u0443 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043f\u0430\u043f\u043a\u0438 <code>\/demo\/node_modules<\/code> \u0438 \u0444\u0430\u0439\u043b\u044b <code>\/demo\/package.json<\/code> \u0438 <code>\/demo\/package-lock.json<\/code>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c\u0441\u044f \u0441 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c\u0438 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>\/demo\/reactapp<\/code><\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 4 &#8212; \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">rm -rf node_modules\/ rm package.json rm package-lock.json<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u043f\u043a\u0443 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a nginx \u0432 \u0440\u0435\u0436\u0438\u043c\u0430\u0445 development \u0438 production.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 5 &#8212; \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 nginx<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"bash\">mkdir nginx mkdir nginx\/development mkdir nginx\/production<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 <code>\/demo\/nginx\/development\/nginx.conf<\/code> \u0437\u0430\u0432\u0435\u0434\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 <\/summary>\n<\/details>\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-355086","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/355086","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=355086"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/355086\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=355086"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=355086"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=355086"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}