{"id":160123,"date":"2012-11-26T13:42:03","date_gmt":"2012-11-26T09:42:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=160123"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=160123","title":{"rendered":"<span class=\"post_title\">WebSocket-\u0447\u0430\u0442 \u043d\u0430 Tornado \u0434\u043b\u044f \u0432\u0430\u0448\u0435\u0433\u043e Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/span>"},"content":{"rendered":"<div class=\"content html_format\">   \t<img decoding=\"async\" src=\"http:\/\/habrastorage.org\/storage2\/af3\/4b4\/0a5\/af34b40a5d32825e460d6c52441101a5.jpg\" alt=\"Tornado\" align=\"right\" title=\"\u041b\u043e\u0433\u043e\u0442\u0438\u043f Tornado\"\/>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0441\u0430\u0439\u0442 <a href=\"http:\/\/backgrounddating.com\/\">backgrounddating.com<\/a> \u0438 <a href=\"http:\/\/habrahabr.ru\/post\/159693\/\">\u043d\u0430\u043f\u0438\u0441\u0430\u043b<\/a> \u043e\u0431 \u044d\u0442\u043e\u043c \u0437\u0434\u0435\u0441\u044c, \u043d\u0430 \u0425\u0430\u0431\u0440\u0430\u0445\u0430\u0431\u0440\u0435. \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u044f \u0443\u0436\u0435 \u0442\u043e\u0433\u0434\u0430 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b \u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u043e \u043e\u0431 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0441\u0430\u0439\u0442\u0430 \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 (\u043a\u0430\u043a \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c, \u0442\u0430\u043a \u0438 \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c) \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u0430\u043b\u043e. \u0418\u0442\u0430\u043a, \u0440\u0435\u0447\u044c \u043f\u043e\u0439\u0434\u0451\u0442 \u043e \u0447\u0430\u0442\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438. \u0417\u0430\u0434\u0430\u0447\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043b\u044e\u0431\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0438, \u0435\u0441\u043b\u0438 \u0443 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u0440\u044b\u0442 \u0447\u0430\u0442 \u0441 \u044d\u0442\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c, \u0442\u043e \u043e\u043d \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0432\u0438\u0434\u0435\u043b \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f (\u0430 \u0432 \u0438\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043c\u043e\u0433 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0436\u0435: \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0447\u0430\u0442\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439).<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u043b\u0438 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0434\u0432\u043e\u0451\u043c, \u0430 \u0433\u0440\u0443\u043f\u043f\u0430\u043c\u0438 \u0438\u0437 \u043b\u044e\u0431\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0442\u0438 \u0447\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u043e: \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043f\u043e \u0441\u0443\u0442\u0438, \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u043d\u0430 \u0442\u0430\u043a\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>  \u0421\u0440\u0430\u0437\u0443 \u0443\u0442\u043e\u0447\u043d\u044e, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 node.js), \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (\u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0435\u0451 <a href=\"https:\/\/github.com\/facebook\/tornado\/blob\/master\/demos\/chat\/chatdemo.py\">\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c<\/a>, \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430: \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u0430\u043d\u0430\u043b\u0430 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 worker \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430). \u042f \u0434\u0430\u0436\u0435 \u043d\u0435 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441\u0430\u043c\u044b\u0439 \u043b\u0443\u0447\u0448\u0438\u0439 (\u043d\u043e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043f\u043e\u0434\u043e\u0448\u0451\u043b \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0445). \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u043c\u044b \u0437\u0434\u0435\u0441\u044c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u0441\u0442\u044b\u043b\u0438 (long polling, Flash) \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 (\u0430 \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 IE, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440), \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u044b, \u0438 \u0434\u0430\u0436\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u0442\u0435\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b WebSocket, \u043d\u043e \u043d\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e (<a href=\"http:\/\/tools.ietf.org\/html\/rfc6455\">RFC 6455<\/a>), \u0430 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0445. \u041e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u00abdraft 76\u00bb (\u043e\u043d\u0430 \u0436\u0435 \u00abhixie-76\u00bb), \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0432 <a href=\"http:\/\/www.tornadoweb.org\/documentation\/websocket.html\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a> Tornado.<br \/>  <a name=\"habracut\"><\/a><br \/>  \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u043e\u0447\u043d\u043e \u2014 \u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0445\u043e\u0440\u043e\u0448\u043e, \u043f\u0440\u0438\u0447\u0451\u043c \u043d\u0435 \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u0430 \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 (\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0445\u043e\u0442\u044c \u043e \u043d\u0451\u043c \u043f\u043e\u043a\u0430 \u0438 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438). \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0435\u0440\u0432\u0435\u0440, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Background Dating \u2014 \u044d\u0442\u043e \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u0430\u043c\u044b\u0439 \u043c\u043b\u0430\u0434\u0448\u0438\u0439 VPS \u043e\u0442 Linode (512 MiB \u043f\u0430\u043c\u044f\u0442\u0438), \u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u043d\u0435 \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u043b\u0430\u0441\u044c \u0431\u043e\u043b\u0435\u0435 20\u201440 \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u043e\u0432, \u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438 \u2014 \u043e\u043a\u043e\u043b\u043e 30%. \u041f\u0440\u0438\u0447\u0451\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c gunicorn (\u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Django) \u0438 PostgreSQL. \u041d\u043e \u0442\u0443\u0442 \u043d\u0435\u0442 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0438 \u0434\u043b\u044f \u043a\u043e\u0433\u043e \u043d\u0435 \u0441\u0435\u043a\u0440\u0435\u0442, \u0447\u0442\u043e Tornado \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0451\u0433\u043a\u0438\u0439, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u043e, \u043d\u043e \u0434\u0430\u0436\u0435 \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441 <a href=\"http:\/\/en.wikipedia.org\/wiki\/C10k_problem\">C10k<\/a> (\u043e \u0447\u0451\u043c \u0443\u0436\u0435 <a href=\"http:\/\/habrahabr.ru\/post\/145796\/\">\u0431\u044b\u043b\u043e<\/a> \u043d\u0430 \u0425\u0430\u0431\u0440\u0430\u0445\u0430\u0431\u0440\u0435).<\/p>\n<p>  \u0418\u0442\u0430\u043a, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/djangoproject.com\/\">Django<\/a> 1.4.2, <a href=\"http:\/\/tornadoweb.org\/\">Tornado<\/a> 2.4, <a href=\"http:\/\/redis.io\/\">Redis<\/a> 2.6.5 \u0438 <a href=\"http:\/\/postgresql.org\/\">PostgreSQL<\/a> 9.2.1 (\u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0421\u0423\u0411\u0414 \u2014 \u0443 Django \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0431\u044d\u043a\u044d\u043d\u0434\u043e\u0432). \u0414\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a Redis \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0434\u043b\u044f Python \u043a\u043b\u0438\u0435\u043d\u0442 <a href=\"https:\/\/github.com\/andymccurdy\/redis-py\">redis-py<\/a>, \u0430 \u0442\u0430\u043a\u0436\u0435 <a href=\"https:\/\/github.com\/evilkost\/brukva\">br\u00fckva<\/a> (\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 Redis-\u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441 Tornado). \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u0441\u0451 \u044d\u0442\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"http:\/\/haproxy.1wt.eu\/\">haproxy<\/a> \u0438 <a href=\"http:\/\/nginx.org\/\">nginx<\/a>, \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 production \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 <a href=\"http:\/\/gunicorn.org\/\">gunicorn<\/a>, \u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0434\u043b\u044f Django \u0438 Tornado \u0431\u0443\u0434\u0435\u0442 <a href=\"http:\/\/supervisord.org\/\">Supervisor<\/a>.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0447\u0443\u0432\u0441\u0442\u0432\u0443\u0435\u0442\u0435, \u0447\u0442\u043e \u0432\u0430\u043c \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0437\u043d\u0430\u043d\u0438\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b \u043d\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043d\u0435\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440, \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435), \u0442\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e, \u0438, \u0435\u0441\u043b\u0438 \u043e\u0441\u0442\u0430\u043d\u0443\u0442\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 (\u0438\u043b\u0438 \u043c\u043d\u0435 \u043f\u043e <a href=\"mailto:aruseni.magiku@gmail.com\">\u043f\u043e\u0447\u0442\u0435<\/a>). \u0422\u0430\u043a\u0436\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0439 \u043f\u043e \u0442\u0435\u043c\u0435 (<a href=\"http:\/\/softwaremaniacs.org\/forum\/django\/32804\/\">1<\/a>, <a href=\"http:\/\/softwaremaniacs.org\/forum\/django\/35701\/\">2<\/a>, <a href=\"http:\/\/softwaremaniacs.org\/forum\/django\/19643\/\">3<\/a>, <a href=\"http:\/\/softwaremaniacs.org\/forum\/python\/22061\/\">4<\/a>, <a href=\"http:\/\/softwaremaniacs.org\/forum\/django\/36629\/\">5<\/a>, <a href=\"http:\/\/softwaremaniacs.org\/forum\/python\/22160\/\">6<\/a>, <a href=\"http:\/\/softwaremaniacs.org\/forum\/python\/39706\/\">7<\/a>) \u043d\u0430 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e\u043c <a href=\"http:\/\/softwaremaniacs.org\/forum\/\">\u0444\u043e\u0440\u0443\u043c\u0435<\/a> Python-\u0433\u0443\u0440\u0443 \u0418\u0432\u0430\u043d\u0430 \u0421\u0430\u0433\u0430\u043b\u0430\u0435\u0432\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 <a href=\"http:\/\/kmike.ru\/files\/django-realtime.pdf\">\u0441\u043b\u0430\u0439\u0434\u044b<\/a> \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u00ab\u0421\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c (\u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 django)\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0435\u0449\u0451 \u043e\u0434\u0438\u043d Python-\u0433\u0443\u0440\u0443 \u041c\u0438\u0445\u0430\u0438\u043b \u041a\u043e\u0440\u043e\u0431\u043e\u0432 \u0447\u0438\u0442\u0430\u043b \u043d\u0430 <a href=\"http:\/\/2011.devconf.ru\/programm\/python_perl\">DevConf 2011<\/a>.<\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Django<\/h3>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0451\u043c Django-\u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u043f\u043e\u044f\u0432\u0438\u0432\u0448\u0443\u044e\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e:<\/p>\n<pre> django-admin.py startproject myproject cd myproject\/ <\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b myproject\/settings.py.<\/p>\n<p>  \u041f\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u0438\u0434\u0435\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Redis-\u0431\u044d\u043a\u044d\u043d\u0434\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0441\u0435\u0441\u0441\u0438\u044f\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u042d\u0442\u043e \u0441\u0442\u043e\u0438\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 (\u043a\u0440\u043e\u043c\u0435 \u0442\u0435\u0445, \u0433\u0434\u0435 \u0432\u044b \u043f\u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Redis, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0442\u0435\u0445, \u0433\u0434\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439). \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 <a href=\"https:\/\/github.com\/martinrusev\/django-redis-sessions\">django-redis-sessions<\/a> (pip install django-redis-sessions) \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445:<\/p>\n<pre><code class=\"python\">SESSION_ENGINE = 'redis_sessions.session' <\/code><\/pre>\n<p>  \u041f\u043e\u0437\u0434\u0440\u0430\u0432\u043b\u044f\u044e, \u0432\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043b\u0438, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0430\u0439\u0442\u0443 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u043e\u0441\u044c \u043d\u0430 1 (Redis \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e\u0447\u0442\u0438 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e). \ud83d\ude42<\/p>\n<p>  \u041a\u0441\u0442\u0430\u0442\u0438, \u0442\u0430\u043a\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0435 \u0432 gitignore \u2014 \u043e\u0431\u044b\u0447\u043d\u043e \u044d\u0442\u043e local_settings.py.<\/p>\n<p>  \u0422\u0443\u0434\u0430 \u0436\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 (SECRET_KEY), \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u043c\u044b\u0441\u043b \u0442\u0443\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0432 local_settings.py \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u044d\u043a\u044d\u043d\u0434 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0431\u044d\u043a\u044d\u043d\u0434 \u0441\u0435\u0441\u0441\u0438\u0439, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0435\u0436\u0438\u043c\u0430 \u043e\u0442\u043b\u0430\u0434\u043a\u0438), \u0430 \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445 Git (\u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0432\u0435\u0440\u0441\u0438\u0439) \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043a\u043b\u044e\u0447\u0430\u0445 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f\u0445.<\/p>\n<p>  \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432 local_settings.py, \u0432\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u0446\u0435 settings.py \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"python\">try:     from local_settings import * except ImportError:     pass <\/code><\/pre>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 (DATABASES), \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432, \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u043a\u043b\u044e\u0447 API (Tornado \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0431\u0443\u0434\u0435\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043a Django \u0438 Django \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u044d\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445), \u0430 \u0442\u0430\u043a\u0436\u0435 URL, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<p>  \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0438 \u0441\u0430\u0439\u0442\u0430 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 (\u0438\u043b\u0438 \u043f\u0440\u0438 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0432 \u0424\u0421) \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u043c\u0435\u0441\u0442\u043e\u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0441\u0432\u0435\u0440\u0445\u0443 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"python\">import os  PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__)) <\/code><\/pre>\n<p>  \u0410 \u0434\u0430\u043b\u0435\u0435, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0443\u0442\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 PROJECT_ROOT.<\/p>\n<p>  \u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<pre><code class=\"python\">STATICFILES_DIRS = (     os.path.join(PROJECT_ROOT, &quot;static&quot;), ) <\/code><\/pre>\n<p>  \u0428\u0430\u0431\u043b\u043e\u043d\u044b:<\/p>\n<pre><code class=\"python\">TEMPLATE_DIRS = (     os.path.join(PROJECT_ROOT, &quot;templates&quot;), ) <\/code><\/pre>\n<p>  \u041a\u043b\u044e\u0447 API \u0438 \u0430\u0434\u0440\u0435\u0441:<\/p>\n<pre><code class=\"python\">API_KEY = '$0m3-U\/\\\/1qu3-K3Y'  SEND_MESSAGE_API_URL = 'http:\/\/127.0.0.1:8000\/messages\/send_message_api' <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u044e\u0447, \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0432\u043e\u0442 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u0447\u043a\u043e\u0439 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 (\u043d\u0430 \u0432\u0430\u0441 \u043e\u0442\u0442\u0443\u0434\u0430, \u043a\u0441\u0442\u0430\u0442\u0438, \u0441\u043c\u0430\u0439\u043b\u0438\u043a \u0441\u043c\u043e\u0442\u0440\u0438\u0442):<\/p>\n<pre> &lt; \/dev\/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo; <\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 myproject (\u0433\u0434\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f settings.py \u0438 local_settings.py) \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438 static \u0438 templates \u0438 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f-\u0447\u0430\u0442\u0430.<\/p>\n<h3>\u0427\u0430\u0442 (Django)<\/h3>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:<\/p>\n<pre> python manage.py startapp privatemessages <\/pre>\n<p>  \u0418 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043c\u043e\u0434\u0435\u043b\u0438 (privatemessages\/models.py):<\/p>\n<pre><code class=\"python\">from django.db import models from django.db.models.signals import post_save  from django.contrib.auth.models import User  # Create your models here.  class Thread(models.Model):     participants = models.ManyToManyField(User)     last_message = models.DateTimeField(null=True, blank=True, db_index=True)  class Message(models.Model):     text = models.TextField()     sender = models.ForeignKey(User)     thread = models.ForeignKey(Thread)     datetime = models.DateTimeField(auto_now_add=True, db_index=True)  def update_last_message_datetime(sender, instance, created, **kwargs):     &quot;&quot;&quot;     Update Thread's last_message field when     a new message is sent.     &quot;&quot;&quot;     if not created:         return      Thread.objects.filter(id=instance.thread.id).update(         last_message=instance.datetime     )  post_save.connect(update_last_message_datetime, sender=Message) <\/code><\/pre>\n<p>  \u0422\u0443\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e \u2014 \u0435\u0441\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u0442\u0440\u0435\u0434\u044b (\u043d\u0438\u0442\u0438). \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u044b\u0445 \u0434\u0432\u0443\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0439 \u0442\u0440\u0435\u0434, \u0438 \u0432\u0441\u0435 \u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u043a \u044d\u0442\u043e\u043c\u0443 \u0442\u0440\u0435\u0434\u0443. \u041a\u043e\u0433\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0442\u043e \u0434\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0442\u0440\u0435\u0434\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 INSTALLED_APPS \u0432 settings.py \u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u0438 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre> python manage.py syncdb <\/pre>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0442\u043a\u0440\u043e\u0435\u043c privatemessages\/views.py \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c 4 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f:  <\/p>\n<ul>\n<li><em>send_message_view<\/em> \u2014 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 Django (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u043b\u044e\u0434\u044c\u043c\u0438)<\/li>\n<li><em>send_message_api_view<\/em> \u2014 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 Tornado<\/li>\n<li><em>messages_view<\/em> \u2014 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u043e\u0432 (\u0441 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u043f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f)<\/li>\n<li><em>chat_view<\/em> \u2014 \u0434\u043b\u044f \u0447\u0430\u0442\u0430 (Django \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0442\u0435\u043c\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0434\u0430\u043b\u044c\u0448\u0435 \u0431\u0440\u0430\u0437\u0443\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043a Tornado-\u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0447\u0435\u0440\u0435\u0437 WS \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c\/\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0438 \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432)<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"python\"># Create your views here.  import json  import redis  from django.shortcuts import render_to_response, get_object_or_404 from django.http import HttpResponse, HttpResponseRedirect from django.template import RequestContext from django.core.urlresolvers import reverse from django.utils import timezone from django.views.decorators.csrf import csrf_exempt from django.conf import settings  from django.contrib.auth.models import User  from privatemessages.models import Thread, Message  from privatemessages.utils import json_response, send_message  def send_message_view(request):     if not request.method == &quot;POST&quot;:         return HttpResponse(&quot;Please use POST.&quot;)      if not request.user.is_authenticated():         return HttpResponse(&quot;Please sign in.&quot;)      message_text = request.POST.get(&quot;message&quot;)      if not message_text:         return HttpResponse(&quot;No message found.&quot;)      if len(message_text) &gt; 10000:         return HttpResponse(&quot;The message is too long.&quot;)      recipient_name = request.POST.get(&quot;recipient_name&quot;)      try:         recipient = User.objects.get(username=recipient_name)     except User.DoesNotExist:         return HttpResponse(&quot;No such user.&quot;)      if recipient == request.user:         return HttpResponse(&quot;You cannot send messages to yourself.&quot;)      thread_queryset = Thread.objects.filter(         participants=recipient     ).filter(         participants=request.user     )      if thread_queryset.exists():         thread = thread_queryset[0]     else:         thread = Thread.objects.create()         thread.participants.add(request.user, recipient)      send_message(                     thread.id,                     request.user.id,                     message_text,                     request.user.username                 )      return HttpResponseRedirect(         reverse('privatemessages.views.messages_view')     )  @csrf_exempt def send_message_api_view(request, thread_id):     if not request.method == &quot;POST&quot;:         return json_response({&quot;error&quot;: &quot;Please use POST.&quot;})      api_key = request.POST.get(&quot;api_key&quot;)      if api_key != settings.API_KEY:         return json_response({&quot;error&quot;: &quot;Please pass a correct API key.&quot;})      try:         thread = Thread.objects.get(id=thread_id)     except Thread.DoesNotExist:         return json_response({&quot;error&quot;: &quot;No such thread.&quot;})      try:         sender = User.objects.get(id=request.POST.get(&quot;sender_id&quot;))     except User.DoesNotExist:         return json_response({&quot;error&quot;: &quot;No such user.&quot;})      message_text = request.POST.get(&quot;message&quot;)      if not message_text:         return json_response({&quot;error&quot;: &quot;No message found.&quot;})      if len(message_text) &gt; 10000:         return json_response({&quot;error&quot;: &quot;The message is too long.&quot;})      send_message(                     thread.id,                     sender.id,                     message_text                 )      return json_response({&quot;status&quot;: &quot;ok&quot;})  def messages_view(request):     if not request.user.is_authenticated():         return HttpResponse(&quot;Please sign in.&quot;)      threads = Thread.objects.filter(         participants=request.user     ).order_by(&quot;-last_message&quot;)      if not threads:         return render_to_response('private_messages.html',                                   {},                                   context_instance=RequestContext(request))      r = redis.StrictRedis()      user_id = str(request.user.id)      for thread in threads:         thread.partner = thread.participants.exclude(id=request.user.id)[0]          thread.total_messages = r.hget(             &quot;&quot;.join([&quot;thread_&quot;, str(thread.id), &quot;_messages&quot;]),             &quot;total_messages&quot;         )      return render_to_response('private_messages.html',                               {                                   &quot;threads&quot;: threads,                               },                               context_instance=RequestContext(request))  def chat_view(request, thread_id):     if not request.user.is_authenticated():         return HttpResponse(&quot;Please sign in.&quot;)      thread = get_object_or_404(         Thread,         id=thread_id,         participants__id=request.user.id     )      messages = thread.message_set.order_by(&quot;-datetime&quot;)[:100]      user_id = str(request.user.id)      r = redis.StrictRedis()      messages_total = r.hget(         &quot;&quot;.join([&quot;thread_&quot;, thread_id, &quot;_messages&quot;]),         &quot;total_messages&quot;     )      messages_sent = r.hget(         &quot;&quot;.join([&quot;thread_&quot;, thread_id, &quot;_messages&quot;]),         &quot;&quot;.join([&quot;from_&quot;, user_id])     )      if messages_total:         messages_total = int(messages_total)     else:         messages_total = 0      if messages_sent:         messages_sent = int(messages_sent)     else:         messages_sent = 0      messages_received = messages_total-messages_sent      partner = thread.participants.exclude(id=request.user.id)[0]      tz = request.COOKIES.get(&quot;timezone&quot;)     if tz:         timezone.activate(tz)      return render_to_response('chat.html',                               {                                   &quot;thread_id&quot;: thread_id,                                   &quot;thread_messages&quot;: messages,                                   &quot;messages_total&quot;: messages_total,                                   &quot;messages_sent&quot;: messages_sent,                                   &quot;messages_received&quot;: messages_received,                                   &quot;partner&quot;: partner,                               },                               context_instance=RequestContext(request)) <\/code><\/pre>\n<p>  \u0418 \u0432\u043e\u0442 privatemessages\/utils.py:<\/p>\n<pre><code class=\"python\">import json  import redis  from django.utils import dateformat  from privatemessages.models import Message  def json_response(obj):     &quot;&quot;&quot;     This function takes a Python object (a dictionary or a list)     as an argument and returns an HttpResponse object containing     the data from the object exported into the JSON format.     &quot;&quot;&quot;     return HttpResponse(json.dumps(obj), content_type=&quot;application\/json&quot;)  def send_message(thread_id,                  sender_id,                  message_text,                  sender_name=None):     &quot;&quot;&quot;     This function takes Thread object id (first argument),     sender id (second argument), message text (third argument)     and can also take sender's name.      It creates a new Message object and increases the     values stored in Redis that represent the total number     of messages for the thread and the number of this thread's     messages sent from this specific user.      If a sender's name is passed, it also publishes     the message in the thread's channel in Redis     (otherwise it is assumed that the message was     already published in the channel).     &quot;&quot;&quot;      message = Message()     message.text = message_text     message.thread_id = thread_id     message.sender_id = sender_id     message.save()      thread_id = str(thread_id)     sender_id = str(sender_id)      r = redis.StrictRedis()      if sender_name:         r.publish(&quot;&quot;.join([&quot;thread_&quot;, thread_id, &quot;_messages&quot;]), json.dumps({             &quot;timestamp&quot;: dateformat.format(message.datetime, 'U'),             &quot;sender&quot;: sender_name,             &quot;text&quot;: message_text,         }))      for key in (&quot;total_messages&quot;, &quot;&quot;.join([&quot;from_&quot;, sender_id])):         r.hincrby(             &quot;&quot;.join([&quot;thread_&quot;, thread_id, &quot;_messages&quot;]),             key,             1         ) <\/code><\/pre>\n<p>  \u041e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 tz.activate(), \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/i18n\/timezones\/\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a> Django \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0447\u0430\u0441\u043e\u0432\u044b\u043c\u0438 \u043f\u043e\u044f\u0441\u0430\u043c\u0438. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0447\u0430\u0441\u043e\u0432\u043e\u043c \u043f\u043e\u044f\u0441\u0435 (\u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u044f\u0437\u044b\u043a\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440), \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 cookie \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c timezone \u2014 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c Django \u0441\u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0434\u0430\u0442\u0443 \u0438 \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043c \u0447\u0430\u0441\u043e\u0432\u043e\u043c \u043f\u043e\u044f\u0441\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c.<\/p>\n<p>  \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u0435, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"http:\/\/www.pageloom.com\/automatic-timezone-detection-with-javascript\">jstz<\/a> (\u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c <a href=\"https:\/\/bitbucket.org\/pellepim\/jstimezonedetect\/downloads\">jstz.min.js<\/a> \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 myproject\/static). \u0415\u0441\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f: \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043c\u043e\u0436\u043d\u043e \u0431\u0440\u0430\u0442\u044c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u044b\u0439 \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0431\u0430\u0437\u044b GeoIP \u0438\u043b\u0438 \u0434\u0430\u0436\u0435 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 (\u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430\u043c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e. \u0447\u0442\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0432\u0440\u0435\u043c\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e) \u2014 \u0442\u0430\u043a\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0437\u043d\u0430\u0442\u044c \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0435\u0433\u043e \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0432\u044b\u0431\u0440\u0430\u043d \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441, \u043d\u043e \u0432\u0440\u0435\u043c\u044f \u0431\u044b\u043b\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043e \u0434\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u044f\u0441\u043d\u043e\u043c\u0443.<\/p>\n<p>  \u041d\u043e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441, \u0442\u043e, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0435\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0435\u0433\u043e \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 (\u0432 \u0438\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438).<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0432\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c <a href=\"http:\/\/pytz.sourceforge.net\/\">pytz<\/a> (pip install pytz) \u2014 \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0447\u0430\u0441\u043e\u0432\u043e\u0439 \u043f\u043e\u044f\u0441 \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u041e\u043b\u0441\u043e\u043d\u0430 (<a href=\"http:\/\/www.iana.org\/time-zones\">IANA time zone database<\/a>).<\/p>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f send_messages \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043e\u043d\u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 hash \u0441 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0440\u0435\u0434\u0430 \u0432 Redis. \u0412 \u044d\u0442\u043e\u043c hash \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0434\u0432\u0430 \u043a\u043b\u044e\u0447\u0430 \u2014 \u043e\u0434\u0438\u043d \u0438\u0437 \u043d\u0438\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u0442\u0440\u0435\u0434\u0435, \u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0442 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u042d\u0442\u0438 \u043a\u043b\u044e\u0447\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u043e\u0431\u0449\u0435\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u0445 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (\u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u044b\u0445 \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0438\u043d\u0443\u0441 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445).<\/p>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0447\u0430\u0442 \u0438 \u0435\u0433\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 WS-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 Tornado-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, Tornado-\u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u043d\u0430\u043b \u0442\u0440\u0435\u0434\u0430 \u0432 Redis, \u0438 \u043f\u0440\u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0442\u0443\u0442 \u0436\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 Pub\/Sub \u0432 Redis (\u043a\u043e\u043c\u0430\u043d\u0434\u044b SUBSCRIBE, UNSUBSCRIBE \u0438 PUBLISH), \u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u043d\u0435\u0439 \u0432 <a href=\"http:\/\/redis.io\/topics\/pubsub\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a> \u043f\u043e Redis.<\/p>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e send_messages \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 send_message_view \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0438\u043c\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f, \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0435 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0440\u0435\u0434\u0430 \u0432 Redis. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 send_message_api_view \u0438\u043c\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f, \u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0443\u0436\u0435 \u0431\u044b\u043b\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u043d\u0430 \u043a\u0430\u043d\u0430\u043b \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0440\u0435\u0434\u0430, \u0435\u0449\u0451 \u0434\u043e \u0432\u044b\u0437\u043e\u0432\u0430 send_message_api_view (\u0442\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u043b\u0438\u0441\u044c \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438, \u043e\u0431\u0449\u0430\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u0432 \u0447\u0430\u0442\u0435 \u2014 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0435).<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b privatemessages\/urls.py \u0438 \u0437\u0430\u0434\u0430\u0434\u0438\u043c urlpatterns \u0434\u043b\u044f Django-\u043c\u0435\u0442\u043e\u0434\u043e\u0432:<\/p>\n<pre><code class=\"python\">from django.conf.urls import patterns, url  urlpatterns = patterns('privatemessages.views',     url(r'^send_message\/$', 'send_message_view'),     url(r'^send_message_api\/(?P&lt;thread_id&gt;\\d+)\/$', 'send_message_api_view'),     url(r'^chat\/(?P&lt;thread_id&gt;\\d+)\/$', 'chat_view'),     url(r'^$', 'messages_view'), ) <\/code><\/pre>\n<p>  \u0418, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u043a\u043b\u044e\u0447\u0438\u043c \u0438\u0445 \u0432 <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/http\/urls\/\">root URLconf<\/a> (myproject\/urls.py):<\/p>\n<pre><code class=\"python\">from django.conf.urls import patterns, include, url  # something else  urlpatterns = patterns('',     # something else      url(r'^messages\/', include('privatemessages.urls')),      # something else ) <\/code><\/pre>\n<p>  \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0441 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c chat.html \u0438 private_messages.html. \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d base.html.<\/p>\n<p>  base.html<\/p>\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;link rel=&quot;stylesheet&quot; type=&quot;text\/css&quot; href=&quot;\/static\/privatemessages.css&quot;&gt; &lt;script type=&quot;text\/javascript&quot; src=&quot;http:\/\/yandex.st\/jquery\/1.8.3\/jquery.min.js&quot;&gt;&lt;\/script&gt; &lt;script type=&quot;text\/javascript&quot; src=&quot;\/static\/jstz.min.js&quot;&gt;&lt;\/script&gt; &lt;script type=&quot;text\/javascript&quot; src=&quot;\/static\/privatemessages.js&quot;&gt;&lt;\/script&gt; {% block head %}{% endblock %} &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text\/html; charset=utf-8&quot;&gt; &lt;title&gt;{% block title %}\u041b\u0438\u0447\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f{% endblock title %}&lt;\/title&gt; &lt;\/head&gt; &lt;body&gt; {% block content %}{% endblock content %} &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  chat.html<\/p>\n<pre><code class=\"html\">{% extends &quot;base.html&quot; %}  {% block title %}{{ partner.username }}{% endblock %}  {% block head %} &lt;script type=&quot;text\/javascript&quot;&gt; $(document).ready(function() {     activate_chat({{ thread_id }}, &quot;{{ user.username }}&quot;, {         &quot;total&quot;: {{ messages_total }},         &quot;sent&quot;: {{ messages_sent }},         &quot;received&quot;: {{ messages_received }}     }); }); &lt;\/script&gt; {% endblock %}  {% block content %} {% load pluralize %} &lt;div class=&quot;chat&quot;&gt;     &lt;div class=&quot;partner&quot;&gt;         &lt;p class=&quot;name&quot;&gt;{{ partner.username }}&lt;\/p&gt;         &lt;p class=&quot;messages&quot;&gt;&lt;span class=&quot;total&quot;&gt;{{ messages_total }}&lt;\/span&gt; {{ messages_total|rupluralize:&quot;\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435,\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f,\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439&quot; }} (&lt;span class=&quot;received&quot;&gt;{{ messages_received }}&lt;\/span&gt; \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043e, &lt;span class=&quot;sent&quot;&gt;{{ messages_sent }}&lt;\/span&gt; \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e)&lt;\/p&gt;     &lt;\/div&gt;     &lt;div class=&quot;conversation&quot;&gt;         {% for message in thread_messages reversed %}         &lt;div class=&quot;message&quot;&gt;              {% if message.sender == user %}&lt;p class=&quot;author we&quot;&gt;&lt;span class=&quot;datetime&quot;&gt;{{ message.datetime|date:&quot;d.m.Y H:i:s&quot; }}&lt;\/span&gt; {{ user.username }}:&lt;\/p&gt;{% else %}&lt;p class=&quot;author partner&quot;&gt;&lt;span class=&quot;datetime&quot;&gt;{{ message.datetime|date:&quot;d.m.Y H:i:s&quot; }}&lt;\/span&gt; {{ partner.username }}:&lt;\/p&gt;{% endif %}             &lt;p class=&quot;message&quot;&gt;{{ message.text|linebreaksbr }}&lt;\/p&gt;         &lt;\/div&gt;         {% endfor %}     &lt;\/div&gt;     &lt;form class=&quot;message_form&quot;&gt;         &lt;div class=&quot;compose&quot;&gt;             &lt;textarea rows=&quot;1&quot; cols=&quot;30&quot; id=&quot;message_textarea&quot;&gt;&lt;\/textarea&gt;         &lt;\/div&gt;         &lt;div class=&quot;send&quot;&gt;             &lt;button class=&quot;btn&quot; type=&quot;button&quot;&gt;\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c&lt;\/button&gt;             &lt;p&gt;\u0412\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043b\u0430\u0432\u0438\u0448 Ctrl + Enter.&lt;\/p&gt;         &lt;\/div&gt;     &lt;\/form&gt; &lt;\/div&gt; {% endblock content %} <\/code><\/pre>\n<p>  private_messages.html<\/p>\n<pre><code class=\"html\">{% extends &quot;base.html&quot; %}  {% block content %} {% load pluralize %} &lt;div class=&quot;private_messages&quot;&gt;     &lt;h1&gt;\u0421\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0438&lt;\/h1&gt;     &lt;div class=&quot;partners&quot;&gt;     {% for thread in threads %}         &lt;p&gt;&lt;a href=&quot;{% url privatemessages.views.chat_view thread.id %}&quot;&gt;{{ thread.partner.username }} ({{ thread.total_messages|default_if_none:&quot;0&quot; }} {{ thread.total_messages|rupluralize:&quot;\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435,\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f,\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439&quot; }})&lt;\/a&gt;&lt;\/p&gt;     {% empty %}         &lt;p&gt;\u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u043e\u0432 \u043d\u0435\u0442.&lt;\/p&gt;     {% endfor %}     &lt;\/div&gt;     &lt;h1&gt;\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435&lt;\/h1&gt;     &lt;form action=&quot;{% url privatemessages.views.send_message_view %}&quot; method=&quot;post&quot; class=&quot;new_message&quot;&gt;         {% csrf_token %}         &lt;p class=&quot;name&quot;&gt;&lt;input name=&quot;recipient_name&quot; placeholder=&quot;\u0418\u043c\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f&quot;&gt;&lt;\/p&gt;         &lt;p&gt;&lt;textarea name=&quot;message&quot; placeholder=&quot;\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435&quot;&gt;&lt;\/textarea&gt;&lt;\/p&gt;         &lt;p&gt;&lt;input type=&quot;submit&quot; value=&quot;\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c&quot;&gt;&lt;\/p&gt;     &lt;\/form&gt; &lt;\/div&gt; {% endblock content %} <\/code><\/pre>\n<p>  \u0418 \u0435\u0449\u0451 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433 privatemessages\/templatetags \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 __init__.py \u0438 pluralize.py.<\/p>\n<p>  privatemessages\/templatetags\/pluralize.py (\u0430\u0432\u0442\u043e\u0440 <a href=\"http:\/\/vas3k.ru\/dev\/django_ru_pluralize\/\">\u0444\u0438\u043b\u044c\u0442\u0440\u0430<\/a> \u2014 V@s3K):<\/p>\n<pre><code class=\"python\">from django import template  register = template.Library()  @register.filter def rupluralize(value, arg):     args = arg.split(&quot;,&quot;)     try:         number = abs(int(value))     except TypeError:         number = 0      a = number % 10     b = number % 100      if (a == 1) and (b != 11):         return args[0]     elif (a &gt;= 2) and (a &lt;= 4) and ((b &lt; 10) or (b &gt;= 20)):         return args[1]     else:         return args[2] <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0438\u043b\u0438 (myproject\/static\/privatemessages.css):<\/p>\n<pre><code class=\"css\">html, body {     height: 100%;     margin: 0; }  body {     font-family: Geneva, Arial, Helvetica, sans-serif;     font-size: 14px;     color: #000;     background: #fff; }  textarea, form p.name input {     border: 1px #d4d4d4 solid; }  form.new_message p {     margin: 4px 0; }  form.new_message p.name input, form.new_message textarea {     width: 300px; }  form.new_message textarea {     height: 100px; }  textarea:focus, input.name:focus {     border-color: #cacaca;     -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 3px rgba(150, 150, 150, 0.5);        -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 3px rgba(150, 150, 150, 0.5);             box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 3px rgba(150, 150, 150, 0.5); }  div.private_messages {     padding: 10px; }  div.private_messages h1 {     margin-top: 0; }  div.private_messages div.partners {     margin-bottom: 30px; }  div.chat {     height: 100%;     min-height: 400px;     min-width: 600px;     position: relative;     background-color: #e0e0e0; }  div.chat div.partner {     height: 50px;     padding: 5px; }  div.chat div.partner p {     margin: 0; }  div.chat div.partner p.name {     font-weight: bold;     margin-bottom: 3px; }  div.chat div.conversation {     position: absolute;     top: 50px;     left: 5px;     right: 5px;     bottom: 140px;     overflow: auto;     padding: 0 5px;     border-style: solid;     border-color: #eee;     border-width: 10px 0;     background-color: #fff;     -webkit-border-radius: 7px;        -moz-border-radius: 7px;             border-radius: 7px; }  div.chat div.conversation div.message {     padding: 5px 0; }  div.chat div.conversation div.message p {     margin: 0; }  div.chat div.conversation div.message p.author.partner {     color: #002c64; }  div.chat div.conversation div.message p.author.we {     color: #216300; }  div.chat div.conversation div.message p.author span.datetime {     font-size: 12px; }  div.chat form.message_form {     position: absolute;     margin: 0;     left: 0;     right: 0;     bottom: 5px;     height: 130px; }  div.chat form.message_form div.outdated_browser_message {     margin: 10px 5px; }  div.chat form.message_form div.compose {     float: left;     height: 100%;     width: 80%;     padding: 0 5px;     -webkit-box-sizing: border-box;        -moz-box-sizing: border-box;             box-sizing: border-box; }  div.chat form.message_form div.compose textarea {     width: 100%;     height: 100%;     margin: 0;     -webkit-box-sizing: border-box;        -moz-box-sizing: border-box;             box-sizing: border-box;     resize: none; }  div.chat form.message_form div.send {     float: left;     height: 100%;     width: 20%;     min-width: 100px;     padding-right: 5px;     -webkit-box-sizing: border-box;        -moz-box-sizing: border-box;             box-sizing: border-box; }  div.chat form.message_form div.send p {     margin-top: 5px;     color: #333; }  div.chat form.message_form div.send button {     width: 100%;     -webkit-box-sizing: border-box;        -moz-box-sizing: border-box;             box-sizing: border-box; } <\/code><\/pre>\n<p>  \u0418 JavaScript (myproject\/static\/privatemessages.js):<\/p>\n<pre><code class=\"javascript\">function getCookie(name) {     var cookieValue = null;     if (document.cookie &amp;&amp; document.cookie != '') {         var cookies = document.cookie.split(';');         for (var i = 0; i &lt; cookies.length; i++) {             var cookie = jQuery.trim(cookies[i]);             \/\/ Does this cookie string begin with the name we want?             if (cookie.substring(0, name.length + 1) == (name + '=')) {                 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));                 break;             }         }     }     return cookieValue; }  function setCookie(key, value) {     document.cookie = escape(key) + '=' + escape(value); }  function getNumEnding(iNumber, aEndings) {     var sEnding, i;     iNumber = iNumber % 100;     if (iNumber&gt;=11 &amp;&amp; iNumber&lt;=19) {         sEnding=aEndings[2];     }     else {         i = iNumber % 10;         switch (i)         {             case (1): sEnding = aEndings[0]; break;             case (2):             case (3):             case (4): sEnding = aEndings[1]; break;             default: sEnding = aEndings[2];         }     }     return sEnding; }  var timezone = getCookie('timezone');  if (timezone == null) {     setCookie(&quot;timezone&quot;, jstz.determine().name()); }  function activate_chat(thread_id, user_name, number_of_messages) {     $(&quot;div.chat form.message_form div.compose textarea&quot;).focus();      function scroll_chat_window() {         $(&quot;div.chat div.conversation&quot;).scrollTop($(&quot;div.chat div.conversation&quot;)[0].scrollHeight);     }      scroll_chat_window();      var ws;      function start_chat_ws() {         ws = new WebSocket(&quot;ws:\/\/127.0.0.1:8888\/&quot; + thread_id + &quot;\/&quot;);         ws.onmessage = function(event) {             var message_data = JSON.parse(event.data);             var date = new Date(message_data.timestamp*1000);             var time = $.map([date.getHours(), date.getMinutes(), date.getSeconds()], function(val, i) {                 return (val &lt; 10) ? '0' + val : val;             });             $(&quot;div.chat div.conversation&quot;).append('&lt;div class=&quot;message&quot;&gt;&lt;p class=&quot;author ' + ((message_data.sender == user_name) ? 'we' : 'partner') + '&quot;&gt;&lt;span class=&quot;datetime&quot;&gt;' + time[0] + ':' + time[1] + ':' + time[2] + '&lt;\/span&gt; ' + message_data.sender + ':&lt;\/p&gt;&lt;p class=&quot;message&quot;&gt;' + message_data.text.replace(\/&amp;\/g,'&amp;amp;').replace(\/&lt;\/g,'&amp;lt;').replace(\/&gt;\/g,'&amp;gt;').replace(\/\\n\/g, '&lt;br \/&gt;') + '&lt;\/p&gt;&lt;\/div&gt;');             scroll_chat_window();             number_of_messages[&quot;total&quot;]++;             if (message_data.sender == user_name) {                 number_of_messages[&quot;sent&quot;]++;             } else {                 number_of_messages[&quot;received&quot;]++;             }             $(&quot;div.chat p.messages&quot;).html('&lt;span class=&quot;total&quot;&gt;' + number_of_messages[&quot;total&quot;] + '&lt;\/span&gt; ' + getNumEnding(number_of_messages[&quot;total&quot;], [&quot;\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435&quot;, &quot;\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f&quot;, &quot;\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439&quot;]) + ' (&lt;span class=&quot;received&quot;&gt;' + number_of_messages[&quot;received&quot;] + '&lt;\/span&gt; \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043e, &lt;span class=&quot;sent&quot;&gt;' + number_of_messages[&quot;sent&quot;] + '&lt;\/span&gt; \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e)');         }         ws.onclose = function(){             \/\/ Try to reconnect in 5 seconds             setTimeout(function() {start_chat_ws()}, 5000);         };     }      if (&quot;WebSocket&quot; in window) {         start_chat_ws();     } else {         $(&quot;form.message_form&quot;).html('&lt;div class=&quot;outdated_browser_message&quot;&gt;&lt;p&gt;&lt;em&gt;\u041e\u0439!&lt;\/em&gt; \u0412\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445:&lt;\/p&gt;&lt;ul&gt;&lt;li&gt;\u0414\u043b\u044f &lt;em&gt;Android&lt;\/em&gt;: &lt;a href=&quot;http:\/\/www.mozilla.org\/ru\/mobile\/&quot;&gt;Firefox&lt;\/a&gt;, &lt;a href=&quot;http:\/\/www.google.com\/intl\/en\/chrome\/browser\/mobile\/android.html&quot;&gt;Google Chrome&lt;\/a&gt;, &lt;a href=&quot;https:\/\/play.google.com\/store\/apps\/details?id=com.opera.browser&quot;&gt;Opera Mobile&lt;\/a&gt;&lt;\/li&gt;&lt;li&gt;\u0414\u043b\u044f &lt;em&gt;Linux&lt;\/em&gt;, &lt;em&gt;Mac OS X&lt;\/em&gt; \u0438 &lt;em&gt;Windows&lt;\/em&gt;: &lt;a href=&quot;http:\/\/www.mozilla.org\/ru\/firefox\/fx\/&quot;&gt;Firefox&lt;\/a&gt;, &lt;a href=&quot;https:\/\/www.google.com\/intl\/ru\/chrome\/browser\/&quot;&gt;Google Chrome&lt;\/a&gt;, &lt;a href=&quot;http:\/\/ru.opera.com\/browser\/download\/&quot;&gt;Opera&lt;\/a&gt;&lt;\/li&gt;&lt;\/ul&gt;&lt;\/div&gt;');         return false;     }      function send_message() {         var textarea = $(&quot;textarea#message_textarea&quot;);         if (textarea.val() == &quot;&quot;) {             return false;         }         if (ws.readyState != WebSocket.OPEN) {             return false;         }         ws.send(textarea.val());         textarea.val(&quot;&quot;);     }      $(&quot;form.message_form div.send button&quot;).click(send_message);      $(&quot;textarea#message_textarea&quot;).keydown(function (e) {         \/\/ Ctrl + Enter         if (e.ctrlKey &amp;&amp; e.keyCode == 13) {             send_message();         }     }); } <\/code><\/pre>\n<p>  \u041f\u0440\u0438 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d Tornado-\u0441\u0435\u0440\u0432\u0435\u0440 (\u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u044b\u043d\u0435\u0441\u0438\u0442\u0435 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e).<\/p>\n<h3>\u0427\u0430\u0442 (Tornado)<\/h3>\n<p>  \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u043e\u0432\u043e\u0435 Tornado-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0432 privatemessages\/tornadoapp.py:<\/p>\n<pre><code class=\"python\">import datetime import json import time import urllib  import brukva import tornado.web import tornado.websocket import tornado.ioloop import tornado.httpclient  from django.conf import settings from django.utils.importlib import import_module  session_engine = import_module(settings.SESSION_ENGINE)  from django.contrib.auth.models import User  from privatemessages.models import Thread  c = brukva.Client() c.connect()  class MainHandler(tornado.web.RequestHandler):     def get(self):         self.set_header('Content-Type', 'text\/plain')         self.write('Hello. :)')  class MessagesHandler(tornado.websocket.WebSocketHandler):     def __init__(self, *args, **kwargs):         super(MessagesHandler, self).__init__(*args, **kwargs)         self.client = brukva.Client()         self.client.connect()      def open(self, thread_id):         session_key = self.get_cookie(settings.SESSION_COOKIE_NAME)         session = session_engine.SessionStore(session_key)         try:             self.user_id = session[&quot;_auth_user_id&quot;]             self.sender_name = User.objects.get(id=self.user_id).username         except (KeyError, User.DoesNotExist):             self.close()             return         if not Thread.objects.filter(             id=thread_id,             participants__id=self.user_id         ).exists():             self.close()             return         self.channel = &quot;&quot;.join(['thread_', thread_id,'_messages'])         self.client.subscribe(self.channel)         self.thread_id = thread_id         self.client.listen(self.show_new_message)      def handle_request(self, response):         pass      def on_message(self, message):         if not message:             return         if len(message) &gt; 10000:             return         c.publish(self.channel, json.dumps({             &quot;timestamp&quot;: int(time.time()),             &quot;sender&quot;: self.sender_name,             &quot;text&quot;: message,         }))         http_client = tornado.httpclient.AsyncHTTPClient()         request = tornado.httpclient.HTTPRequest(             &quot;&quot;.join([                         settings.SEND_MESSAGE_API_URL,                         &quot;\/&quot;,                         self.thread_id,                         &quot;\/&quot;                     ]),             method=&quot;POST&quot;,             body=urllib.urlencode({                 &quot;message&quot;: message.encode(&quot;utf-8&quot;),                 &quot;api_key&quot;: settings.API_KEY,                 &quot;sender_id&quot;: self.user_id,             })         )         http_client.fetch(request, self.handle_request)      def show_new_message(self, result):         self.write_message(str(result.body))      def on_close(self):         try:             self.client.unsubscribe(self.channel)         except AttributeError:             pass         def check():             if self.client.connection.in_progress:                 tornado.ioloop.IOLoop.instance().add_timeout(                     datetime.timedelta(0.00001),                     check                 )             else:                 self.client.disconnect()         tornado.ioloop.IOLoop.instance().add_timeout(             datetime.timedelta(0.00001),             check         )  application = tornado.web.Application([     (r&quot;\/&quot;, MainHandler),     (r'\/(?P&lt;thread_id&gt;\\d+)\/', MessagesHandler), ]) <\/code><\/pre>\n<p>  \u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0451 \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e, \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c tornado.ioloop. \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443 \u0441\u0435\u0441\u0441\u0438\u0438 (\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0435\u0433\u043e \u0438\u043c\u0435\u043d\u0438 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445). \u042d\u0442\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f, \u0442\u043e \u0435\u0441\u0442\u044c \u0432 \u044d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u0435 \u043a \u044d\u0442\u043e\u043c\u0443 Tornado-\u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0431\u0443\u0434\u0443\u0442 \u0436\u0434\u0430\u0442\u044c. \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0442\u043e \u044d\u0442\u043e \u043b\u0435\u0433\u043a\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c, \u043d\u043e, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0435 \u0444\u0430\u043a\u0442, \u0447\u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0430 \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043f\u043e\u0434\u0443\u043c\u0430\u0439\u0442\u0435, \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u043b\u0438 \u044d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u041f\u043e \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0432\u043e\u0434\u0443 \u0440\u0435\u0431\u044f\u0442\u0430 \u0438\u0437 Friendfeed (\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 Tornado) \u0432\u044b\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u043d\u0435 \u0440\u0430\u0437. \u0412\u043e\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0446\u0438\u0442\u0430\u0442\u0430 \u0438\u0437 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0411\u044d\u043d\u0430 \u0414\u0430\u0440\u043d\u044d\u043b\u043b\u0430 (Ben Darnell):<\/p>\n<blockquote><p>Friendfeed uses mysql, with the standard synchronous MySQLdb module (http:\/\/bret.appspot.com\/entry\/how-friendfeed-uses-mysql). Friendfeed&#8217;s philosophy is that for things that are fast and under your control (i.e. memcache and database \u2014 and if your database isn&#8217;t fast, rethink how you&#8217;re querying it), you should just call them synchronously because it&#8217;s not worth the complexity of managing callbacks. Asynchronous code is for things that are likely to be slow in ways you can&#8217;t do anything about (e.g. external APIs) or when you want to suspend a request for an indefinite amount of time (long polling). A library like adisp shifts the balance somewhat since it makes async interfaces much simpler to use, although there are still issues like the fact that generator coroutines aren&#8217;t composable like normal function calls.  <\/p><\/blockquote>\n<p>  \u0422\u043e \u0435\u0441\u0442\u044c, \u0433\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u0435\u0441\u043b\u0438 \u0432\u0430\u0448\u0430 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e \u2014 \u0437\u043d\u0430\u0447\u0438\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439, \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0443\u0442 \u043c\u0430\u043b\u043e \u0447\u0435\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442. \u041b\u0438\u0431\u043e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e \u0432\u044b \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043b\u0438 \u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u2014 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u043b\u044c\u0437\u044b, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443, \u0430 \u043d\u0435 \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u0435 \u0441\u0438\u043c\u043f\u0442\u043e\u043c\u044b.<\/p>\n<p>  \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c Tornado-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0447\u0435\u0440\u0435\u0437 management-\u043a\u043e\u043c\u0430\u043d\u0434\u0443. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0430\u043c \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f <a href=\"http:\/\/stackoverflow.com\/questions\/2180415\/using-django-database-layer-outside-of-django\">\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0443\u044e \u0441\u0440\u0435\u0434\u0443 Django<\/a> \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a ORM \u0438 \u0432\u0441\u0435\u043c\u0443 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u043c\u0443.<\/p>\n<p>  \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u044e management-\u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043e\u0447\u0435\u043d\u044c \u043b\u0435\u0433\u043a\u043e. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0435 privatemessages \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e management, \u0430 \u0432 \u043d\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e commands.<\/p>\n<p>  \u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 privatemessages\/management \u0438 \u0432 privatemessages\/management\/commands \u043f\u043e \u0444\u0430\u0439\u043b\u0443 __init__.py (\u0435\u0441\u043b\u0438 \u043a\u0442\u043e-\u0442\u043e \u0432\u0434\u0440\u0443\u0433 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442, \u0437\u0430\u0447\u0435\u043c \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f, \u0442\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0432 <a href=\"http:\/\/docs.python.org\/2\/tutorial\/modules.html\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>).<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b privatemessages\/management\/commands\/starttornadoapp.py:<\/p>\n<pre><code class=\"python\">import signal import time  import tornado.httpserver import tornado.ioloop  from django.core.management.base import BaseCommand, CommandError  from privatemessages.tornadoapp import application  class Command(BaseCommand):     args = '[port_number]'     help = 'Starts the Tornado application for message handling.'      def sig_handler(self, sig, frame):         &quot;&quot;&quot;Catch signal and init callback&quot;&quot;&quot;         tornado.ioloop.IOLoop.instance().add_callback(self.shutdown)      def shutdown(self):         &quot;&quot;&quot;Stop server and add callback to stop i\/o loop&quot;&quot;&quot;         self.http_server.stop()          io_loop = tornado.ioloop.IOLoop.instance()         io_loop.add_timeout(time.time() + 2, io_loop.stop)      def handle(self, *args, **options):         if len(args) == 1:             try:                 port = int(args[0])             except ValueError:                 raise CommandError('Invalid port number specified')         else:             port = 8888          self.http_server = tornado.httpserver.HTTPServer(application)         self.http_server.listen(port, address=&quot;127.0.0.1&quot;)          # Init signals handler         signal.signal(signal.SIGTERM, self.sig_handler)          # This will also catch KeyboardInterrupt exception         signal.signal(signal.SIGINT, self.sig_handler)          tornado.ioloop.IOLoop.instance().start() <\/code><\/pre>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u0433\u043d\u0430\u043b\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u0433\u043d\u0430\u043b SIGINT, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 Ctrl + C) \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0447\u0442\u043e-\u043b\u0438\u0431\u043e \u0435\u0449\u0451, \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435. \u041f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443 \u043c\u043e\u0436\u043d\u043e <a href=\"http:\/\/codemehanika.org\/blog\/2011-10-28-graceful-stop-tornado.html\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c<\/h3>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 (\u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 myproject \u0438 privatemessages, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0444\u0430\u0439\u043b manage.py) \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 development-\u0441\u0435\u0440\u0432\u0435\u0440 Django \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 Tornado.<\/p>\n<pre> python manage.py runserver python manage.py starttornadoapp <\/pre>\n<p>  \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u043a\u043b\u0430\u0434\u043a\u0430\u0445 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430, \u043b\u0438\u0431\u043e \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u043a\u043b\u0430\u0434\u043a\u0430\u0445 <a href=\"http:\/\/www.opennet.ru\/base\/sys\/screen_intro.txt.html\">screen<\/a> (\u0435\u0441\u043b\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0435\u0441\u044c \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043f\u043e SSH \u0438 \u0432\u0430\u043c \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u043d\u0443 SSH-\u0441\u0435\u0441\u0441\u0438\u044e).<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 8000 \u0443 \u0432\u0430\u0441 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0441\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 Django, \u0430 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 8888 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0441\u0435\u0440\u0432\u0435\u0440 Tornado.<\/p>\n<p>  \u0421\u043f\u0438\u0441\u043e\u043a \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u043e\u0432 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435:<\/p>\n<p>  <a href=\"http:\/\/127.0.0.1:8000\/messages\/\">http:\/\/127.0.0.1:8000\/messages\/<\/a><\/p>\n<p>  \u041e\u0442\u0442\u0443\u0434\u0430 \u0436\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0447\u0430\u0442\u043e\u0432 \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 (\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0432 \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0444\u043e\u0440\u043c\u0443).<\/p>\n<p>  \u0418\u043c\u0435\u0439\u0442\u0435 \u0432 \u0432\u0438\u0434\u0443, \u0447\u0442\u043e \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043d\u0430 \u0432\u0430\u0448\u0435\u043c Django-\u0441\u0430\u0439\u0442\u0435. \u041e \u0442\u043e\u043c, \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e, \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0432 <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/topics\/auth\/\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043b\u0435\u043d\u0438\u0432\u044b\u0445 \u2014 \u043f\u0440\u043e\u0441\u0442\u043e <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/contrib\/admin\/\">\u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/a> \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435\u0441\u044c \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e.<\/p>\n<h3>Deployment<\/h3>\n<p>  \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u041f\u041e:<\/p>\n<ul>\n<li><a href=\"http:\/\/haproxy.1wt.eu\/\">haproxy<\/a> \u2014 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 80<\/li>\n<li><a href=\"http:\/\/nginx.org\/\">nginx<\/a> \u2014 \u0440\u0430\u0437\u0434\u0430\u0447\u0430 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 + \u0440\u0435\u0432\u0435\u0440\u0441-\u043f\u0440\u043e\u043a\u0441\u0438 \u0434\u043b\u044f gunicorn, \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 8100<\/li>\n<li><a href=\"http:\/\/supervisord.org\/\">Supervisor<\/a> \u2014 \u0437\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Tornado \u043d\u0430 \u043f\u043e\u0440\u0442\u0430\u0445 8000\u20148003 (4 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430) \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Django (\u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c gunicorn) \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 8150<\/li>\n<\/ul>\n<p>  \u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c Supervisor. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e (\u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 Supervisor \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 Ubuntu) \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \/etc\/supervisor\/conf.d \u0444\u0430\u0439\u043b\u044b django.conf \u0438 tornadoapp.conf. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e Supervisor \u0431\u0443\u0434\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u044d\u0442\u0438 \u0444\u0430\u0439\u043b\u044b (\u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u043a\u0446\u0438\u044f include \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0439 files = \/etc\/supervisor\/conf.d\/*.conf).<\/p>\n<p>  django.conf<\/p>\n<pre> [program:django] command=gunicorn_django --workers 4 -b 127.0.0.1:8150 directory=\/home\/yourusername\/myproject user=yourusername autostart=true autorestart=true <\/pre>\n<p>  tornadoapp.conf<\/p>\n<pre> process_name = tornado-%(process_num)s user = yourusername directory = \/home\/yourusername\/myproject command = python manage.py starttornadoapp %(process_num)s # Increase numprocs to run multiple processes on different ports. # Note that the chat demo won't actually work in that configuration # because it assumes all listeners are in one process. numprocs = 4 numprocs_start = 8000 autostart=true autorestart=true <\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 supervisor \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0432\u044b\u0432\u043e\u0434 \u043a\u043e\u043c\u0430\u043d\u0434\u044b supervisorctl status.<\/p>\n<p>  \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443 \u0432\u0441\u0435\u0445 5 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 (gunicorn \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0446\u0435\u0441\u0441) \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 RUNNING \u0438 uptime \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0442\u0435\u043c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u0440\u043e\u0448\u043b\u043e \u0441 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Supervisor.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0438 Django-\u0441\u0435\u0440\u0432\u0435\u0440\u044b, \u0438 Tornado-\u0441\u0435\u0440\u0432\u0435\u0440\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044c SSH-\u0442\u0443\u043d\u043d\u0435\u043b\u044c \u0434\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432\u0430\u0448 \u0441\u0430\u0439\u0442 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043e\u0431\u0440\u0430\u0449\u0430\u044f\u0441\u044c \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043a \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043e\u0440\u0442\u0443 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0430\u0434\u0440\u0435\u0441\u0435.<\/p>\n<p>  \u0422\u043e, \u0435\u0441\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre> ssh -L 8000:localhost:8150 someverycoolserver.com <\/pre>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0435 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 127.0.0.1:8000 (SSH-\u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0435\u0440\u0435\u0434\u0430\u0441\u0442 \u0432\u0430\u0448 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 127.0.0.1:8150 \u0432 \u0441\u0432\u043e\u0435\u0439 \u0441\u0435\u0442\u0438 \u2014 \u0433\u0434\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c).<\/p>\n<p>  \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c Tornado-\u0441\u0435\u0440\u0432\u0435\u0440\u044b. \u041e\u043d\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043d\u0430 \u043f\u043e\u0440\u0442\u0430\u0445 8000\u20148003.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u044b Django \u0438 Tornado \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442, \u0442\u043e \u0432\u0430\u043c \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c nginx \u0438 haproxy.<\/p>\n<p>  \u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f nginx:<\/p>\n<pre> server {     listen 127.0.0.1:8100;     server_name someverycoolserver.com;      # no security problem here, since \/ is always passed to upstream     root \/home\/yourusername\/myproject\/myproject\/static\/;      ## Compression     # src: http:\/\/www.ruby-forum.com\/topic\/141251     # src: http:\/\/wiki.brightbox.co.uk\/docs:nginx      gzip on;     gzip_http_version 1.0;     gzip_comp_level 2;     gzip_proxied any;     gzip_min_length  1100;     gzip_buffers 16 8k;     gzip_types text\/plain text\/html text\/css application\/x-javascript text\/xml application\/xml application\/xml+rss text\/javascript;          # Some version of IE 6 don't handle compression well on some mime-types, so just disable for them     gzip_disable &quot;MSIE [1-6].(?!.*SV1)&quot;;          # Set a vary header so downstream proxies don't send cached gzipped content to IE6     gzip_vary on;     ## \/Compression      location \/static\/admin\/ {         # this changes depending on your python version         root \/usr\/local\/lib\/python2.7\/dist-packages\/django\/contrib\/admin\/;     }      location \/robots.txt {         alias \/home\/yourusername\/myproject\/myproject\/robots.txt;     }      location \/favicon.ico {         alias \/home\/yourusername\/myproject\/myproject\/img\/favicon.ico;         expires 3d;     }      location \/static\/ {         root \/home\/yourusername\/myproject\/myproject\/;         expires 3d;     }      location \/ {         proxy_pass_header Server;         proxy_set_header Host $http_host;         proxy_redirect off;         proxy_set_header X-Real-IP $remote_addr;         proxy_set_header X-Scheme $scheme;         proxy_connect_timeout 10;         proxy_read_timeout 10;         proxy_pass http:\/\/localhost:8150\/;     } } <\/pre>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0442\u0443\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0442\u0440\u0451\u0445 \u0434\u043d\u0435\u0439. \u0414\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a \u0441\u0442\u043e\u0438\u0442 \u043b\u0438\u0431\u043e \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0432\u044b \u0442\u043e\u0447\u043d\u043e \u0437\u043d\u0430\u0435\u0442\u0435, \u0447\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442\u0435 \u0442\u0430\u043c \u043c\u0435\u043d\u044f\u0442\u044c (\u0430 \u043e\u0431\u044b\u0447\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u0432\u0441\u0451-\u0442\u0430\u043a\u0438 \u043d\u0443\u0436\u043d\u043e), \u043b\u0438\u0431\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u0443\u044e \u0442\u0435\u0445\u043d\u0438\u043a\u0443 static files versioning (\u043e\u0431\u044b\u0447\u043d\u043e \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043a \u0438\u0445 \u0430\u0434\u0440\u0435\u0441\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f query string, \u0438 \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f \u043d\u0430 \u0434\u0438\u0441\u043a\u0435, \u0442\u043e query string \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f). \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u044d\u0442\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u043c\u0438\u043c\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e (\u043c\u0438\u043d\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e) CSS \u0438 JS \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/github.com\/miracle2k\/django-assets\">django-assets<\/a>.<\/p>\n<p>  \u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 haproxy:<\/p>\n<pre> global     maxconn 10000 # Total Max Connections. This is dependent on ulimit     nbproc 2  defaults     mode http     option redispatch     maxconn 2000     contimeout 5000     clitimeout 50000     srvtimeout 50000     option httpclose  frontend all 0.0.0.0:80     timeout client 86400000      acl is_chat hdr_beg(host) -i chat     use_backend socket_backend if is_chat      default_backend www_backend  backend www_backend     option forwardfor # This sets X-Forwarded-For     timeout server 30000     timeout connect 4000     server server1 localhost:8100  backend socket_backend     balance roundrobin     option forwardfor # This sets X-Forwarded-For     no option httpclose # To match the `Connection` header for the websocket protocol rev. 76     option http-server-close     option http-pretend-keepalive     timeout queue 5000     timeout server 86400000     timeout connect 86400000     server server1 localhost:8000 weight 1 maxconn 5000 check     server server2 localhost:8001 weight 1 maxconn 5000 check     server server2 localhost:8002 weight 1 maxconn 5000 check     server server2 localhost:8003 weight 1 maxconn 5000 check <\/pre>\n<p>  \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u043c \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, Host \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 chat, \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 localhost:8000, localhost:8001, localhost:8002 \u0438 localhost:8003, \u0430 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430 localhost:8100.<\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 haproxy \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 80-\u043c \u043f\u043e\u0440\u0442\u0443 \u043d\u0430 \u0432\u0441\u0435\u0445 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f IPv4-\u0430\u0434\u0440\u0435\u0441\u0430\u0445. \u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c IPv6 (\u0430 \u044d\u0442\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0438\u0434\u0435\u044f, \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0432\u0430\u0448 \u0445\u043e\u0441\u0442\u0438\u043d\u0433\/\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440), \u0442\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 frontend \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 bind \u0441 \u0432\u0430\u0448\u0438\u043c IPv6-\u0430\u0434\u0440\u0435\u0441\u043e\u043c \u0438 80-\u043c \u043f\u043e\u0440\u0442\u043e\u043c \u0447\u0435\u0440\u0435\u0437 \u0434\u0432\u043e\u0435\u0442\u043e\u0447\u0438\u0435.<\/p>\n<p>  \u0418\u043c\u0435\u0439\u0442\u0435 \u0432 \u0432\u0438\u0434\u0443, \u0447\u0442\u043e \u0443 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432\u0430\u0448 IPv6-\u0430\u0434\u0440\u0435\u0441 \u043c\u043e\u0436\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f (\u0435\u0441\u043b\u0438, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u0435 AAAA-\u0437\u0430\u043f\u0438\u0441\u044c \u0432 DNS), \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c. \u0422\u0430\u043a\u043e\u0435 \u0431\u044b\u0432\u0430\u0435\u0442 \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0430\u0442\u043e\u0440\u044b \u0438\u0445 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u0432\u0441\u0451 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e. \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u2014 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d \u0434\u043b\u044f IPv6, \u043b\u0438\u0431\u043e \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 <a href=\"http:\/\/en.wikipedia.org\/wiki\/IPv6_brokenness_and_DNS_whitelisting\">DNS whitelisting<\/a>. \u0422\u0430\u043a <a href=\"http:\/\/events.yandex.ru\/talks\/325\/\">\u0434\u0435\u043b\u0430\u0435\u0442<\/a>, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u042f\u043d\u0434\u0435\u043a\u0441 \u2014 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d\u0438 \u0441 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043b\u044e\u0431\u044f\u0442 \u0438 \u0445\u043e\u0442\u044f\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c IPv6, \u043d\u043e \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043e\u043d\u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u0442\u0435\u0440\u044f\u0442\u044c 1\u20142 \u043f\u0440\u043e\u0446\u0435\u043d\u0442\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (\u0434\u043b\u044f \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e).<\/p>\n<p>  \u041a\u0441\u0442\u0430\u0442\u0438, Tornado-\u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u0435, \u0430 \u043d\u0435 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0440\u0442\u0443 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a \u2014 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f\u0445 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043e\u0447\u0435\u043d\u044c \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043b\u044e\u0431\u044b\u043c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u043f\u043e\u0440\u0442\u0430\u043c (\u043d\u0435 80 \u0438 \u043d\u0435 443).<\/p>\n<p>  \u0412\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c haproxy \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0432\u044b\u0431\u0438\u0440\u0430\u043b backend \u043d\u0435 \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443 Host, \u0430 <a href=\"https:\/\/gist.github.com\/3767467\">\u043f\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u044e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 Upgrade<\/a> \u2014 \u0442\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0438 Django, \u0438 Tornado \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0438 \u0442\u043e\u043c \u0436\u0435 \u0434\u043e\u043c\u0435\u043d\u0435 (\u0432\u043e\u043e\u0431\u0449\u0435 \u0431\u0435\u0437 \u043f\u043e\u0434\u0434\u043e\u043c\u0435\u043d\u043e\u0432), \u043d\u043e WS-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441 Tornado-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438, \u0430 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u2014 \u0441 Django-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438.<\/p>\n<p>  \u041a\u0430\u043a \u0432\u0438\u0434\u0438\u0442\u0435, \u0432 \u0446\u0435\u043b\u043e\u043c \u0432\u0441\u0451 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043d\u043e\u0432\u043e\u0439 \u0442\u0435\u043c\u0435, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e, \u0430 \u0435\u0441\u043b\u0438 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u043d\u0435 \u0432\u0441\u0451, \u0442\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 (\u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 Django \u0438 Tornado \u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0432\u0435\u0449\u0430\u0445 \u043f\u0440\u043e\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0443\u0437\u043d\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432), \u0444\u043e\u0440\u0443\u043c\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0441 \u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u043e\u043a\u043b\u0430\u0434\u043e\u0432. \u0421\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u0443\u0439\u0442\u0435\u0441\u044c \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0439\u0442\u0435 \u043d\u0430\u0434 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438! \u0412\u0441\u0435\u043c \u0443\u0434\u0430\u0447\u0438 \u0438 \u043f\u0440\u0438\u044f\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.      \t   \t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/160123\/\"> http:\/\/habrahabr.ru\/post\/160123\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\">   \t<img decoding=\"async\" src=\"http:\/\/habrastorage.org\/storage2\/af3\/4b4\/0a5\/af34b40a5d32825e460d6c52441101a5.jpg\" alt=\"Tornado\" align=\"right\" title=\"\u041b\u043e\u0433\u043e\u0442\u0438\u043f Tornado\"\/>\u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043b \u0441\u0430\u0439\u0442 <a href=\"http:\/\/backgrounddating.com\/\">backgrounddating.com<\/a> \u0438 <a href=\"http:\/\/habrahabr.ru\/post\/159693\/\">\u043d\u0430\u043f\u0438\u0441\u0430\u043b<\/a> \u043e\u0431 \u044d\u0442\u043e\u043c \u0437\u0434\u0435\u0441\u044c, \u043d\u0430 \u0425\u0430\u0431\u0440\u0430\u0445\u0430\u0431\u0440\u0435. \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u044f \u0443\u0436\u0435 \u0442\u043e\u0433\u0434\u0430 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u043b \u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043d\u043e \u043e\u0431 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0441\u0430\u0439\u0442\u0430 \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435, \u0447\u0442\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 (\u043a\u0430\u043a \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c, \u0442\u0430\u043a \u0438 \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c) \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443 \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u0430\u043b\u043e. \u0418\u0442\u0430\u043a, \u0440\u0435\u0447\u044c \u043f\u043e\u0439\u0434\u0451\u0442 \u043e \u0447\u0430\u0442\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438. \u0417\u0430\u0434\u0430\u0447\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043b\u044e\u0431\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0438, \u0435\u0441\u043b\u0438 \u0443 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u0440\u044b\u0442 \u0447\u0430\u0442 \u0441 \u044d\u0442\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c, \u0442\u043e \u043e\u043d \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0432\u0438\u0434\u0435\u043b \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f (\u0430 \u0432 \u0438\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043c\u043e\u0433 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0436\u0435: \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0447\u0430\u0442\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439).<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u043b\u0438 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0434\u0432\u043e\u0451\u043c, \u0430 \u0433\u0440\u0443\u043f\u043f\u0430\u043c\u0438 \u0438\u0437 \u043b\u044e\u0431\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0442\u0438 \u0447\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0440\u043d\u043e: \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043f\u043e \u0441\u0443\u0442\u0438, \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u0430 \u043d\u0430 \u0442\u0430\u043a\u043e\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>  \u0421\u0440\u0430\u0437\u0443 \u0443\u0442\u043e\u0447\u043d\u044e, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 node.js), \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 (\u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0435\u0451 <a href=\"https:\/\/github.com\/facebook\/tornado\/blob\/master\/demos\/chat\/chatdemo.py\">\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c<\/a>, \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430: \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u0430\u043d\u0430\u043b\u0430 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 worker \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430). \u042f \u0434\u0430\u0436\u0435 \u043d\u0435 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441\u0430\u043c\u044b\u0439 \u043b\u0443\u0447\u0448\u0438\u0439 (\u043d\u043e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043f\u043e\u0434\u043e\u0448\u0451\u043b \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0445). \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u043c\u044b \u0437\u0434\u0435\u0441\u044c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u0441\u0442\u044b\u043b\u0438 (long polling, Flash) \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 (\u0430 \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 IE, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440), \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u0432\u0435\u0431-\u0441\u043e\u043a\u0435\u0442\u044b, \u0438 \u0434\u0430\u0436\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u0442\u0435\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0436\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b WebSocket, \u043d\u043e \u043d\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e (<a href=\"http:\/\/tools.ietf.org\/html\/rfc6455\">RFC 6455<\/a>), \u0430 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0445. \u041e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u00abdraft 76\u00bb (\u043e\u043d\u0430 \u0436\u0435 \u00abhixie-76\u00bb), \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0432 <a href=\"http:\/\/www.tornadoweb.org\/documentation\/websocket.html\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a> Tornado.  <\/p>\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-160123","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/160123","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=160123"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/160123\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=160123"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=160123"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=160123"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}