{"id":300174,"date":"2020-03-16T09:00:12","date_gmt":"2020-03-16T09:00:12","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=300174"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=300174","title":{"rendered":"Nuxt + Django + GraphQL \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/492486\/\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cm\/nl\/wm\/cmnlwmcwqu2drhdusjqe2nn6luq.jpeg\"\/><\/p>\n<p>  <\/p>\n<h2 id=\"predislovie\">\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>  <\/p>\n<p><strong>Nuxt<\/strong> \u2014 &quot;\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430\u0434 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c Vue&quot; \u0438\u043b\u0438 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Vue-based \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043b\u0443\u0447\u0448\u0438\u0445 \u043f\u0440\u0430\u043a\u0442\u0438\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 Vue. \u0421\u0440\u0435\u0434\u0438 \u043d\u0438\u0445: \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f; \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u0435\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0432\u0438\u0434\u0435 Nuxt \u043c\u043e\u0434\u0443\u043b\u0435\u0439; \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/vuex.vuejs.org\/ru\/\">Vuex<\/a> \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u043b\u044e\u0431\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e; \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0438 \u043f\u0440\u0435\u0434\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 <a href=\"https:\/\/ssr.vuejs.org\/ru\/#%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%BD%D1%8B%D0%B9-%D1%80%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B8%D0%BD%D0%B3-ssr\">SSR<\/a> \u0441 <a href=\"https:\/\/vue-loader-v14.vuejs.org\/ru\/features\/hot-reload.html\">hot-reloading&#8217;\u043e\u043c<\/a><\/p>\n<p>  <\/p>\n<p><strong>Django<\/strong> \u2014 \u0441\u0430\u043c\u044b\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 \u043f\u043e\u0447\u0442\u0438 \u0441\u0430\u043c\u043e\u043c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u2014 Python. \u0421\u0430\u043c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u0443\u044e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u043a\u0430\u043a &quot;\u0412\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u043f\u0435\u0440\u0444\u0435\u043a\u0446\u0438\u043e\u043d\u0438\u0441\u0442\u043e\u0432 \u0441 \u0434\u0435\u0434\u043b\u0430\u0439\u043d\u0430\u043c\u0438&quot;. \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435 &quot;\u0432\u0441\u0451 \u0432 \u043e\u0434\u043d\u043e\u043c&quot; \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u043a\u0440\u0430\u0442\u0447\u0430\u0439\u0448\u0438\u0435 \u0441\u0440\u043e\u043a\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c MVP \u0432\u0430\u0448\u0435\u0433\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p><strong>GraphQL<\/strong> \u2014 \u044f\u0437\u044b\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0435\u0439 Facebook. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c\u0441\u044f \u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u0445 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u044d\u0442\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a <strong>Apollo<\/strong> \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u0438 <strong>graphene<\/strong> \u0434\u043b\u044f \u0431\u044d\u043a\u0435\u043d\u0434\u0430.<\/p>\n<p>  <\/p>\n<h2 id=\"o-chem-i-dlya-kogo-eta-statya\">\u041e \u0447\u0435\u043c \u0438 \u0434\u043b\u044f \u043a\u043e\u0433\u043e \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f<\/h2>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0437\u043d\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c dev-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e <a href=\"https:\/\/ru.wikipedia.org\/wiki\/\u041e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0435_\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\">SPA<\/a> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 server side \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u043e\u043c, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 Django \u0438 Nuxt, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c GraphQL API.  <\/p>\n<p>  \u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0437\u0430\u0434\u0430\u0447, \u044f \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0445 \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u0441\u0442\u0435\u043a\u0435.  <\/p>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438 \u043d\u043e\u0432\u0438\u0447\u043a\u0430\u043c \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 (\u043a\u043e\u0438\u043c, \u0431\u0443\u0434\u0443 \u0447\u0435\u0441\u0442\u0435\u043d, \u044f \u0441\u0447\u0438\u0442\u0430\u044e \u0438 \u0441\u0435\u0431\u044f), \u0438 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u0441\u044b\u043b\u043e\u043a.<\/p>\n<p>  <\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u0432\u044b \u0447\u0438\u0442\u0430\u0435\u0442\u0435 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435, \u044f \u0434\u0435\u043b\u0430\u044e \u0441\u043c\u0435\u043b\u043e\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u043f\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0432\u044b \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u0442\u0435 \u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0441\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u044f \u0441\u0442\u0430\u0440\u0430\u043b\u0441\u044f \u043f\u043e\u0434\u0431\u0438\u0440\u0430\u0442\u044c \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u044d\u0442\u0438\u043c \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e.<\/p>\n<p>  <\/p>\n<p>\u0418\u0441\u043a\u0440\u0435\u043d\u0435 \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0445\u043e\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0442\u0435\u043c \u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0441\u0442\u0430\u043c, \u043a\u0442\u043e \u0440\u0435\u0448\u0438\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0431\u0430\u0437\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0445 \u0432\u044b\u0448\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0430\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442 \u0432\u0441\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u043c\u0441\u044f \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0447\u0430\u0441\u044b \u0438 \u0434\u043d\u0438 \u0432 \u043f\u043e\u0438\u0441\u043a\u0430\u0445 \u043f\u0440\u0438\u0447\u0438\u043d \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0449\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c, \u0430 \u0437\u0430\u0442\u0435\u043c \u0438 \u0438\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0441\u0442\u0438\u0441\u044c \u043f\u043e\u044d\u0442\u0430\u043f\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438\u0442\u044c\u0441\u044f \u0447\u0442\u043e \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e.<\/p>\n<p>  <\/p>\n<h2 id=\"pered-nachalom\">\u041f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c<\/h2>\n<p>  <\/p>\n<p>\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0443\u0436\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d <a href=\"https:\/\/nodejs.org\/ru\/\">node.js<\/a> \u0438 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440 <a href=\"https:\/\/www.python.org\/downloads\/\">python<\/a>. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u0438: <strong>13.9<\/strong> \u0438 <strong>3.7<\/strong> \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. <\/p>\n<p>  <\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f python \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/webdevblog.ru\/pipenv-rukovodstvo-po-novomu-instrumentu-python\/\">pipenv<\/a>.<\/p>\n<p>  <\/p>\n<p>\u041a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0431\u043e\u043b\u043e\u0447\u043a\u0435 bash. \u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c Windows, \u0442\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434 <code>cd<\/code>, <code>mv<\/code>, <code>mkdir<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u0438, \u0438 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043a\u0440\u043e\u0441\u0441-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0439 \u043f\u0440\u0438\u0440\u043e\u0434\u0435 python \u0438 node, \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u041e\u0421.<\/p>\n<p>  <\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f Sqlite, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>  <\/p>\n<p>\u0412\u0435\u0440\u0441\u0438\u0438 \u0432\u0441\u0435\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 <a href=\"https:\/\/github.com\/IngvarListard\/nuxt-django-graphql-example\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a> \u0441\u0442\u0430\u0442\u044c\u0438. \u041d\u0438\u0436\u0435 \u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u0442\u0435, \u0447\u0442\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<p>  <\/p>\n<p><strong>Python \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/strong><\/p>\n<p>  <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430<\/th>\n<th>\u0412\u0435\u0440\u0441\u0438\u044f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/docs.djangoproject.com\/en\/2.2\/releases\/2.2\/\">django<\/a><\/td>\n<td>2.2<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.graphene-python.org\/projects\/django\/en\/latest\/\">graphene-django<\/a><\/td>\n<td>2.8.2<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/adamchainz\/django-cors-headers\">django-cors-headers<\/a><\/td>\n<td>3.2<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>  <\/p>\n<p><strong>Javascript \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/strong><\/p>\n<p>  <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430<\/th>\n<th>\u0412\u0435\u0440\u0441\u0438\u044f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/nuxtjs.org\">Nuxt<\/a><\/td>\n<td>2.11<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/nuxt-community\/apollo-module\">nuxtjs\/apollo<\/a><\/td>\n<td>4.0.1<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/v15.vuetifyjs.com\/en\/\">nuxtjs\/vuetify<\/a><\/td>\n<td>0.5.5<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/microcipcip\/cookie-universal\/tree\/master\/packages\/cookie-universal-nuxt\">cookie-universal-nuxt<\/a><\/td>\n<td>2.1.2<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/github.com\/apollographql\/graphql-tag\">graphql-tag<\/a><\/td>\n<td>2.10<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>  <\/p>\n<h2 id=\"pristupim\">\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c<\/h2>\n<p>  <\/p>\n<h2 id=\"django\">Django<\/h2>\n<p>  <\/p>\n<h3 id=\"sozdanie-proekta-i-okruzheniya\">\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c pipenv. \u0414\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">pip install pipenv<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0430\u0432\u0430 \u0441\u0443\u043f\u0435\u0440\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0422\u0430\u043a\u0436\u0435 pipenv \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0432\u0430\u0448\u0435\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0432 \u043d\u0435\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 <code>pipenv<\/code>. \u0412 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u043f\u0443\u0442\u0438 <code>~\/Documents\/projects\/todo-list<\/code>. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u044d\u0442\u0443 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043d\u0435\u0451.<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">mkdir ~\/Documents\/projects\/todo-list cd ~\/Documents\/projects\/todo-list<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c <code>django<\/code> \u0438 <code>graphene_django<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">pipenv install django==2.2.10 graphene_django<\/code><\/pre>\n<p>  <\/p>\n<p>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <code>graphene_django<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0443 GraphQL API \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 Django ORM. \u041e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u043e, \u043d\u043e \u043a\u0430\u043a \u043f\u043e \u043c\u043d\u0435, \u0441\u043e \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446 \u0411\u0414 \u0438 \u0444\u0440\u043e\u043d\u0442\u043e\u043c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u044b\u043c.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 pipenv. \u0414\u0430\u043b\u0435\u0435 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0432\u0441\u0435 \u043a\u043e\u043c\u043c\u0430\u043d\u0434\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">pipenv shell  # \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 pipenv<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442 Django. <\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">django-admin createapp backend<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"nastroyka\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/h3>\n<p>  <\/p>\n<h4 id=\"perenos-managepy\"><strong>\u041f\u0435\u0440\u0435\u043d\u043e\u0441 manage.py<\/strong><\/h4>\n<p>  <\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434 \u043d\u0430\u0448\u0435\u0433\u043e todo-\u043b\u0438\u0441\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u0438\u043c\u0435\u0442\u044c \u0432\u0441\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 Django \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>manage.py<\/code>, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0435\u0433\u043e \u0438\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>backend<\/code> \u043d\u0430 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u043e\u0432\u044b\u0448\u0435. <\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e, \u0438\u0437 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">mv backend\/manage.py .<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0444\u0430\u0439\u043b\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0430\u0439\u043b\u0430 <code>manage.py<\/code>.<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># manage.py import os import sys  if __name__ == &quot;__main__&quot;:     # \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0443\u0442\u044c \u043a \u0444\u0430\u0439\u043b\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430     os.environ.setdefault(&quot;DJANGO_SETTINGS_MODULE&quot;, &quot;backend.backend.settings&quot;)     ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>backend\/backend\/settings.py<\/code> \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043a \u0432\u0438\u0434\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">ROOT_URLCONF = 'backend.backend.urls' WSGI_APPLICATION = 'backend.backend.wsgi.application'<\/code><\/pre>\n<p>  <\/p>\n<h4 id=\"dobavlenie-graphene_django\"><strong>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 graphene_django<\/strong><\/h4>\n<p>  <\/p>\n<p>\u0412 \u0444\u0430\u0439\u043b\u0435 <code>backend\/backend\/settings.py<\/code> \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>INSTALLED_APPS<\/code> \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 <code>graphene_django<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># backend\/backend\/settings.py  INSTALLED_APPS = [   ...,   'graphene_django', ]<\/code><\/pre>\n<p>  <\/p>\n<h4 id=\"proveryaem-rabotosposobnost\"><strong>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c<\/strong><\/h4>\n<p>  <\/p>\n<pre><code class=\"python\">python manage.py runserver<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 <code>8000<\/code>. \u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 <a href=\"http:\/\/localhost:8000\/\">http:\/\/localhost:8000\/<\/a>, \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0441 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u0439:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Django hello<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/hh\/b-\/ry\/hhb-rytssx5jg9nspydgu6lwenc.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h4 id=\"nastroyka-graphene\"><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 graphene<\/strong><\/h4>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0438\u0436\u0435 <code>http:\/\/localhost:8000\/<\/code> \u0443\u0436\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0442\u044c \u043d\u0430\u0441 \u0440\u0430\u043a\u0435\u0442\u043e\u0439. \u0412 \u0444\u0430\u0439\u043b\u0435 <code>backend\/backend\/urls.py<\/code><\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># backend\/backend\/urls.py from django.contrib import admin from django.urls import path from graphene_django.views import GraphQLView from django.conf import settings  urlpatterns = [     path('admin\/', admin.site.urls),     # graphiql - \u043c\u0438\u043d\u0438 IDE \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 graphql \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432     path('graphql\/', GraphQLView.as_view(graphiql=settings.DEBUG)) ]<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0443\u0441\u0442\u0443\u044e <a href=\"https:\/\/xsltdev.ru\/react\/graphql\/schemas-and-types\/\">\u0441\u0445\u0435\u043c\u0443<\/a>, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0444\u0430\u0439\u043b\u0435 <code>backend\/backend\/api.py<\/code><\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># backend\/todo_list\/api.py import graphene schema = graphene.Schema()<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>GRAPHENE<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0443\u043a\u0430\u0436\u0435\u043c \u043f\u0443\u0442\u044c \u0434\u043e \u043d\u0430\u0448\u0435\u0439 \u0441\u0445\u0435\u043c\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># \/backend\/backend\/settings.py GRAPHENE = {     'SCHEMA': 'backend.backend.api.schema', }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440 \u0443\u0436\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>runserver<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">python manage.py runserver<\/code><\/pre>\n<p>  <\/p>\n<p>\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 <a href=\"http:\/\/localhost:8000\/graphql\/\">http:\/\/localhost:8000\/graphql\/<\/a>. \u0422\u0430\u043c \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u0442\u044c \u0442\u0430 \u0441\u0430\u043c\u0430\u044f \u043c\u0438\u043d\u0438 &quot;IDE&quot; <a href=\"https:\/\/github.com\/graphql\/graphiql\">GrapiQL<\/a>:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">GraphiQL<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/pt\/jb\/nv\/ptjbnvouc67igph8iswnrys656g.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041d\u0438\u0447\u0435\u0433\u043e \u0441\u0442\u0440\u0430\u0448\u043d\u043e\u0433\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0441 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430. \u041e\u043d\u0430 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0430\u0448\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u0443\u0441\u0442\u0430. \u041c\u044b \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u043c \u044d\u0442\u043e \u043f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<p>  <\/p>\n<h3 id=\"prilozhenie-todo_list\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 todo_list<\/h3>\n<p>  <\/p>\n<h4 id=\"sozdanie-prilozheniya\"><strong>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/strong><\/h4>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 todo_list \u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u043a \u043d\u0435\u043c\u0443. \u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0439\u0442\u0435, \u0447\u0442\u043e \u0432\u0441\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f pipenv:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cd backend django-admin startapp todo_list<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043a\u0440\u0438\u043f\u0442 <code>django-admin<\/code> \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u0433\u0434\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u0440\u0435\u043d\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0444\u0430\u0439\u043b <code>backend\/todo_list\/apps.py<\/code>, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">from django.apps import AppConfig  class TodoListConfig(AppConfig):     name = 'backend.todo_list'<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430\u0448\u0435 \u043d\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 <code>INSTALLED_APPS<\/code>, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <code>settings.py<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># backend\/backend\/settings.py INSTALLED_APPS = [     ...,     'backend.todo_list',     ... ]<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u0438 <code>Todo<\/code> \u0438 <code>Category<\/code> \u0432 \u0444\u0430\u0439\u043b <code>backend\/todo_list\/models.py<\/code>:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">models.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># backend\/todo_list\/models.py from datetime import timedelta  from django.db import models from django.utils import timezone  class Category(models.Model):     name = models.CharField(max_length=100, unique=True)      class Meta:         verbose_name = '\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f'         verbose_name_plural = '\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438'      def __str__(self):         return self.name  def get_due_date():     &quot;&quot;&quot; \u041d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0434\u0430\u0451\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0434\u0435\u043d\u044c &quot;&quot;&quot;     return timezone.now() + timedelta(days=1)  class Todo(models.Model):     title = models.CharField(max_length=250)     text = models.TextField(blank=True)     created_date = models.DateField(auto_now_add=True)     due_date = models.DateField(default=get_due_date)     category = models.ForeignKey(Category, related_name='todo_list', on_delete=models.PROTECT)     done = models.BooleanField(default=False)      class Meta:         verbose_name = '\u0417\u0430\u0434\u0430\u0447\u0430'         verbose_name_plural = '\u0417\u0430\u0434\u0430\u0447\u0438'      def __str__(self):         return self.title<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0448\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043b\u0438\u0441\u044c \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u0411\u0414, \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435: <\/p>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b <a href=\"https:\/\/djbook.ru\/rel1.7\/topics\/migrations.html\">\u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439<\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u0448\u0430 \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0441\u0445\u0435\u043c\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">python manage.py makemigrations<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a\u0438\u043c \u0432\u044b\u0432\u043e\u0434\u043e\u043c:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/za\/dk\/tt\/zadktt1beqf8wd6wt2t7ps3d1qy.png\"\/><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>migrate<\/code>. \u0422.\u043a. \u044d\u0442\u043e \u043f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0441\u043a\u0440\u0438\u043f\u0442\u0430 <code>migrate<\/code>, \u0443 \u043d\u0430\u0441 \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 Django:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">python manage.py migrate<\/code><\/pre>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0412\u044b\u0432\u043e\u0434 \u043a\u043e\u043d\u0441\u043e\u043b\u0438<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ss\/cr\/yo\/sscryoufym2z282jrfldthrscjw.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h4 id=\"sozdanie-graphql-api\"><strong>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 GraphQL API<\/strong><\/h4>\n<p>  <\/p>\n<p>\u041e\u043f\u0438\u0448\u0435\u043c <a href=\"https:\/\/xsltdev.ru\/react\/graphql\/schemas-and-types\/\">\u0442\u0438\u043f\u044b<\/a>, <a href=\"https:\/\/xsltdev.ru\/react\/graphql\/queries-and-mutations\/\">\u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043c\u0443\u0442\u0430\u0446\u0438\u0438<\/a> \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u043d\u043e\u0432\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <code>todo_list<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <code>schema.py<\/code>, \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">schema.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># backend\/todo_list\/schema.py import graphene from graphene_django import DjangoObjectType  from backend.todo_list.models import Todo, Category  # \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e graphene_django \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u0442\u0438\u043f\u044b \u043a \u043c\u043e\u0434\u0435\u043b\u044f\u043c, # \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0445\u043e\u0434\u0438\u0442\u044c \u043f\u043e \u0432\u0441\u0435\u0439 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u043a \u0443\u0433\u043e\u0434\u043d\u043e, # \u043f\u0440\u044f\u043c\u043e \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 GraphiQL. # \u041e\u0434\u043d\u0430\u043a\u043e \u0431\u0443\u0434\u044c\u0442\u0435 \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u044b, \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e # \u0441 \u0444\u0440\u043e\u043d\u0442\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0447\u0440\u0435\u0432\u0430\u0442\u043e \u043f\u0440\u0438 \u0440\u043e\u0441\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0414\u0443\u043c\u0430\u044e \u0442\u0430\u043a\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 # \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 CRUD \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. class CategoryNode(DjangoObjectType):     class Meta:         model = Category  class TodoNode(DjangoObjectType):     class Meta:         model = Todo  class Query(graphene.ObjectType):     &quot;&quot;&quot; \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 &quot;&quot;&quot;     todo_list = graphene.List(TodoNode)     categories = graphene.List(CategoryNode)      def resolve_todo_list(self, info):         return Todo.objects.all().order_by('-id')      def resolve_categories(self, info):         return Category.objects.all()  class Mutation(graphene.ObjectType):     &quot;&quot;&quot; \u0412 \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0442\u0438\u043f\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u0435 \u0437\u0430 \u043a\u0430\u043b\u0430\u043c\u0431\u0443\u0440),     \u0442\u0438\u043f\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0442\u0438\u043f\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445     &quot;&quot;&quot;     add_todo = graphene.Field(TodoNode,                               title=graphene.String(required=True),                               text=graphene.String(),                               due_date=graphene.Date(required=True),                               category=graphene.String(required=True))     remove_todo = graphene.Field(graphene.Boolean, todo_id=graphene.ID())     toggle_todo = graphene.Field(TodoNode, todo_id=graphene.ID())      def resolve_add_todo(self, info, **kwargs):         category, _ = Category.objects.get_or_create(name=kwargs.pop('category'))         return Todo.objects.create(category=category, **kwargs)      def resolve_remove_todo(self, info, todo_id):         try:             Todo.objects.get(id=todo_id).delete()         except Todo.DoesNotExist:             return False         return True      def resolve_toggle_todo(self, info, todo_id):         todo = Todo.objects.get(id=todo_id)         todo.done = not todo.done         todo.save()         return todo<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0430\u0448\u0443 \u0441\u0445\u0435\u043c\u0443. \u041a\u0430\u043a \u0432\u044b, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043f\u043e\u043c\u043d\u0438\u0442\u0435 \u0441\u0445\u0435\u043c\u0443 \u043c\u044b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>api.py<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># backend\/backend\/api.py import graphene from backend.todo_list.schema import Query, Mutation schema = graphene.Schema(query=Query, mutation=Mutation)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043d\u044f\u0442\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0435\u0435, \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/post\/461939\/\">\u044d\u0442\u0443<\/a> \u0441\u0442\u0430\u0442\u044c\u044e \u043d\u0430 \u0425\u0430\u0431\u0440\u0435, \u0438\u043b\u0438 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 <a href=\"https:\/\/docs.graphene-python.org\/en\/latest\/types\/\">Graphene<\/a> (\u0430\u043d\u0433\u043b.).<\/p>\n<p>  <\/p>\n<h4 id=\"proverka-api\"><strong>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 API<\/strong><\/h4>\n<p>  <\/p>\n<p>ID \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u0445 \u043d\u0438\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f \u0441 ID \u0432\u0430\u0448\u0438\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439.<\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>runserver<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">python manage.py runserver<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0434\u0435\u043c \u043f\u043e \u043f\u0443\u0442\u0438 <a href=\"http:\/\/localhost:8000\/graphql\/\">http:\/\/localhost:8000\/graphql\/<\/a>. \u0422\u0430\u043c \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0442\u044c \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>graphiql<\/code>. \u0418 \u043a\u0430\u043a \u0432\u044b, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u043e\u043f\u0430\u043b\u0430. <\/p>\n<p>  <\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0438\u0435\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043c\u0443\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">addTodo<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><strong>\u0417\u0430\u043f\u0440\u043e\u0441<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">  mutation(     $title: String!     $text: String     $dueDate: Date!     $category: String!   ) {     addTodo(       title: $title       text: $text       dueDate: $dueDate       category: $category     ) {       todo {         id         title         text         done         createdDate         dueDate         category {           id           name         }       }     }   }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">{   &quot;title&quot;: &quot;First Todo&quot;,   &quot;text&quot;: &quot;Just do it!&quot;,   &quot;dueDate&quot;: &quot;2020-10-17&quot;,   &quot;category&quot;: &quot;\u0420\u0430\u0431\u043e\u0442\u0430&quot; }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/strong><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yg\/wi\/lo\/ygwilohcsxhxvwn0x65lk661nt0.png\"\/><\/p>\n<p>  <\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u044d\u0442\u043e\u0439 \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u0443 \u043d\u0430\u0441 \u0441\u043e\u0437\u0434\u0430\u043b\u043e\u0441\u044c \u0434\u0432\u0435 \u0437\u0430\u043f\u0438\u0441\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>Todo<\/code> \u0442.\u043a. \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u0443\u0442\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430;<\/li>\n<li><code>Category<\/code>, \u0442.\u043a. \u0432 \u0431\u0430\u0437\u0435 \u043d\u0435 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c &quot;\u0420\u0430\u0431\u043e\u0442\u0430&quot;, \u0430 \u043c\u0435\u0442\u043e\u0434 <code>get_or_create<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u0437\u0430 \u0441\u0435\u0431\u044f \u0441\u0430\u043c.<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">todoList \u0438 categories<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><strong>\u0417\u0430\u043f\u0440\u043e\u0441<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">{   todoList {     id     title     text     createdDate     dueDate category {       id       name     }   }   categories {     id     name   } }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/strong>:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/vu\/a6\/ho\/vua6horn_mwn6fvz2souvalge7e.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">toggleTodo<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><strong>\u041c\u0443\u0442\u0430\u0446\u0438\u044f<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">mutation ($todoId: ID) {   toggleTodo(todoId: $todoId) {     id     title     text     createdDate     dueDate     category {       id       name     }     done   } }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">{   &quot;todoId&quot;: &quot;1&quot; }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/strong>:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oa\/ng\/cw\/oangcw2rkfy2clb-sgjfgbrghzw.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">removeTodo<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><strong>\u041c\u0443\u0442\u0430\u0446\u0438\u044f<\/strong><\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">mutation ($todoId: ID) {   removeTodo(todoId: $todoId) }<\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435<\/strong> \u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u043c\u0443\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p>  <\/p>\n<p><strong>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/strong><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xo\/vn\/26\/xovn268dblwy2d4gp97ahgnve6s.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0431\u043b\u0438\u0436\u0435 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c \u0438 \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433\u0438\u0435\u0439 GraphQL, \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 <a href=\"https:\/\/habr.com\/ru\/post\/335050\/\">\u044d\u0442\u043e\u0439<\/a> \u0441\u0442\u0430\u0442\u044c\u0435\u0439 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435.<\/p>\n<p>  <\/p>\n<h2 id=\"nuxt\">Nuxt<\/h2>\n<p>  <\/p>\n<h3 id=\"sozdanie-nuxt-prilozheniya\">\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Nuxt \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h3>\n<p>  <\/p>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 <code>Nuxt<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npx create-nuxt-app frontend<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 \u0441\u043a\u0440\u0438\u043f\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430 \u0432\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. \u041c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c, \u0447\u0442\u043e \u0437\u0430\u0445\u043e\u0442\u0438\u0442\u0435, \u043d\u043e \u0438\u0437 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0445 \u043f\u0443\u043d\u043a\u0442\u043e\u0432 \u044f \u0431\u044b \u043f\u043e\u0441\u043e\u0432\u0435\u0442\u043e\u0432\u0430\u043b \u0432\u044b\u0431\u0440\u0430\u0442\u044c &quot;Custom UI Framework: vuetify&quot;, \u0442.\u043a. \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d, \u0438 &quot;Rendering mode: Universal&quot;, \u0442.\u043a. \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u043c\u0435\u043d\u043d\u043e \u0441 SSR.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u043c\u043e\u0435\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438:<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/sv\/cm\/av\/svcmav9eve7fwvxkvks75i7b3-y.png\"\/><\/p>\n<p>  <\/p>\n<p>\u041d\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f. \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432\u0430\u043c \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0430\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cd frontend npm run dev<\/code><\/pre>\n<p>  <\/p>\n<p>\u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043d\u0430 <a href=\"http:\/\/localhost:3000\">http:\/\/localhost:3000<\/a>. \u0422\u0430\u043c \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u043d\u0430 \u0436\u0434\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f Nuxt + Vuetify:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Nuxt + Vuetify<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oi\/me\/o_\/oimeo_qzmt-juuzhixs20put1cy.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h3 id=\"perenos-konfiguracionnyh-faylov\">\u041f\u0435\u0440\u0435\u043d\u043e\u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432<\/h3>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u044f \u0433\u043e\u0432\u043e\u0440\u0438\u043b \u0440\u0430\u043d\u0435\u0435, \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434 \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0443 \u043d\u0430\u0441 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u043e\u0432\u044b\u0448\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0437 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">cd frontend mv node_modules .. mv nuxt.config.js .. mv .gitignore .. mv package-lock.json .. mv package.json .. mv .prettierrc .. mv .eslintrc.js .. mv .editorconfig .. rm -rf .git<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 <code>nuxt.config.js<\/code> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ nuxt.config.js export default {   ...,   rootDir: 'frontend',   ... }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0435\u0449\u0435 \u0440\u0430\u0437 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0432 \u0437\u0430\u043f\u0443\u0441\u043a dev-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0443\u0436\u0435 \u0438\u0437 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npm run dev<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"verstka-funkcionalnogo-maketa\">\u0412\u0435\u0440\u0441\u0442\u043a\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0430\u043a\u0435\u0442\u0430<\/h3>\n<p>  <\/p>\n<p>\u041b\u044e\u0431\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c <code>v-<\/code> \u044d\u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 UI-toolkit&#8217;a Vuetify. \u0423 \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f <a href=\"https:\/\/v15.vuetifyjs.com\/ru\/getting-started\/quick-start\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0443\u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0442\u043e\u0442 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u0441\u043c\u0435\u043b\u043e \u0432\u0431\u0438\u0432\u0430\u0439\u0442\u0435 \u0432 \u0433\u0443\u0433\u043b <code>v-component-name<\/code>. \u0422\u043e\u043b\u044c\u043a\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0439\u0442\u0435, \u0447\u0442\u043e \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u044f vuetify 1.5.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u043e\u0434\u0438\u043c \u0444\u0430\u0439\u043b <code>frontend\/layouts\/default.vue<\/code> \u043a \u0432\u0438\u0434\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;template&gt;   &lt;v-app&gt;     &lt;v-content&gt;       &lt;v-container&gt;         &lt;nuxt \/&gt;       &lt;\/v-container&gt;     &lt;\/v-content&gt;   &lt;\/v-app&gt; &lt;\/template&gt;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043d\u043e\u0432\u043e\u0433\u043e <code>Todo<\/code> \u043f\u043e \u043f\u0443\u0442\u0438 <code>frontend\/components\/NewTodoForm.vue<\/code>:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">NewTodoForm.vue<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!-- frontend\/components\/NewTodoForm.vue --&gt; &lt;template&gt;   &lt;v-form ref=&quot;form&quot; v-model=&quot;valid&quot;&gt;     &lt;v-card&gt;       &lt;v-card-text class=&quot;pt-0 mt-0&quot;&gt;         &lt;v-layout row wrap&gt;           &lt;v-flex xs8&gt;             &lt;!-- \u041f\u043e\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u0438\u043c\u0435\u043d\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 --&gt;             &lt;v-text-field               v-model=&quot;newTodo.title&quot;               :rules=&quot;[nonEmptyField]&quot;               label=&quot;\u0417\u0430\u0434\u0430\u0447\u0430&quot;               prepend-icon=&quot;check_circle_outline&quot;             \/&gt;           &lt;\/v-flex&gt;           &lt;v-flex xs4&gt;             &lt;!-- \u041f\u043e\u043b\u0435 \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0430\u0442\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 --&gt;             &lt;v-menu               ref=&quot;menu&quot;               v-model=&quot;menu&quot;               :close-on-content-click=&quot;false&quot;               :nudge-right=&quot;40&quot;               :return-value.sync=&quot;newTodo.dueDate&quot;               lazy               transition=&quot;scale-transition&quot;               offset-y               full-width               min-width=&quot;290px&quot;             &gt;               &lt;template v-slot:activator=&quot;{ on }&quot;&gt;                 &lt;v-text-field                   v-model=&quot;newTodo.dueDate&quot;                   :rules=&quot;[nonEmptyField]&quot;                   v-on=&quot;on&quot;                   label=&quot;\u0414\u0430\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f&quot;                   prepend-icon=&quot;event&quot;                   readonly                 \/&gt;               &lt;\/template&gt;               &lt;v-date-picker                 v-model=&quot;newTodo.dueDate&quot;                 no-title                 scrollable                 locale=&quot;ru-ru&quot;                 first-day-of-week=&quot;1&quot;               &gt;                 &lt;v-spacer \/&gt;                 &lt;v-btn @click=&quot;menu = false&quot; flat color=&quot;primary&quot;&gt;\u041e\u0442\u043c\u0435\u043d\u0430&lt;\/v-btn&gt;                 &lt;v-btn                   @click=&quot;$refs.menu.save(newTodo.dueDate)&quot;                   flat                   color=&quot;primary&quot;                   &gt;\u0412\u044b\u0431\u0440\u0430\u0442\u044c&lt;\/v-btn                 &gt;               &lt;\/v-date-picker&gt;             &lt;\/v-menu&gt;           &lt;\/v-flex&gt;           &lt;v-flex xs12&gt;             &lt;v-textarea               v-model=&quot;newTodo.text&quot;               :rules=&quot;[nonEmptyField]&quot;               label=&quot;\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435&quot;               prepend-icon=&quot;description&quot;               hide-details               rows=&quot;1&quot;               class=&quot;py-0 my-0&quot;             \/&gt;           &lt;\/v-flex&gt;         &lt;\/v-layout&gt;       &lt;\/v-card-text&gt;       &lt;v-card-actions&gt;         &lt;!-- \u0421\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439. \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 --&gt;         &lt;v-combobox           v-model=&quot;newTodo.category&quot;           :rules=&quot;[nonEmptyField]&quot;           :items=&quot;categories&quot;           hide-details           label=&quot;\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f&quot;           class=&quot;my-0 mx-2 mb-2 pt-0&quot;           prepend-icon=&quot;category&quot;         \/&gt;         &lt;v-spacer \/&gt;         &lt;v-btn :disabled=&quot;!valid&quot; @click=&quot;add&quot; color=&quot;blue lighten-1&quot; flat           &gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c&lt;\/v-btn         &gt;       &lt;\/v-card-actions&gt;     &lt;\/v-card&gt;   &lt;\/v-form&gt; &lt;\/template&gt;  &lt;script&gt; export default {   name: 'NewTodoForm',   data() {     return {       newTodo: null,       categories: ['\u0414\u043e\u043c', '\u0420\u0430\u0431\u043e\u0442\u0430', '\u0421\u0435\u043c\u044c\u044f', '\u0423\u0447\u0435\u0431\u0430'],       valid: false,       menu: false,       nonEmptyField: text =&gt;         text ? !!text.length : '\u041f\u043e\u043b\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043f\u0443\u0441\u0442\u044b\u043c'     }   },   created() {     this.clear()   },   methods: {     add() {       this.$emit('add', this.newTodo)       this.clear()       this.$refs.form.reset()     },     clear() {       this.newTodo = {         title: '',         text: '',         dueDate: '',         category: ''       }     }   } } &lt;\/script&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e <code>Todo<\/code>, \u0442\u0430\u043c \u0436\u0435:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">TodoItem.vue<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!-- frontend\/components\/TodoItem.vue --&gt; &lt;template&gt;   &lt;v-card&gt;     &lt;v-card-title class=&quot;pb-1&quot; style=&quot;overflow-wrap: break-word;&quot;&gt;       &lt;b&gt;{{ todo.title }}&lt;\/b&gt;       &lt;v-spacer \/&gt;       &lt;v-btn         @click=&quot;$emit('delete', todo.id)&quot;         flat         small         icon         style=&quot;position: absolute; right: 0; top: 0&quot;       &gt;         &lt;v-icon :disabled=&quot;$nuxt.isServer&quot; small&gt;close&lt;\/v-icon&gt;       &lt;\/v-btn&gt;     &lt;\/v-card-title&gt;     &lt;v-card-text class=&quot;py-1&quot;&gt;       &lt;v-layout row justyfy-center align-center&gt;         &lt;v-flex xs11 style=&quot;overflow-wrap: break-word;&quot;&gt;           {{ todo.text }}         &lt;\/v-flex&gt;         &lt;v-flex xs1&gt;           &lt;div style=&quot;text-align: right;&quot;&gt;             &lt;v-checkbox               v-model=&quot;todo.done&quot;               hide-details               class=&quot;pa-0 ma-0&quot;               style=&quot;display: inline-block;&quot;               color=&quot;green lighten-1&quot;             \/&gt;           &lt;\/div&gt;         &lt;\/v-flex&gt;       &lt;\/v-layout&gt;     &lt;\/v-card-text&gt;     &lt;v-card-actions&gt;       &lt;span class=&quot;grey--text&quot;&gt;         \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u043e &lt;v-icon small&gt;event&lt;\/v-icon&gt; {{ todo.dueDate }} | \u0421\u043e\u0437\u0434\u0430\u043d\u043e         &lt;v-icon small&gt;calendar_today&lt;\/v-icon&gt; {{ todo.createdDate }}       &lt;\/span&gt;       &lt;v-spacer \/&gt;       &lt;span class=&quot;grey--text&quot;&gt;         &lt;v-icon small&gt;category&lt;\/v-icon&gt;\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f: {{ todo.category }}       &lt;\/span&gt;     &lt;\/v-card-actions&gt;   &lt;\/v-card&gt; &lt;\/template&gt;  &lt;script&gt; export default {   name: 'TodoItem',   props: {     todo: {       type: Object,       default: () =&gt; ({})     }   } } &lt;\/script&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0432\u0441\u0442\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0432 <code>index.vue<\/code>, \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u044b\u0431\u044b:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.vue<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!-- frontend\/pages\/index.vue --&gt; &lt;template&gt;   &lt;v-layout row wrap justify-center&gt;     &lt;v-flex xs8 class=&quot;pb-1&quot;&gt;       &lt;new-todo-form @add=&quot;addTodo&quot; \/&gt;     &lt;\/v-flex&gt;     &lt;v-flex v-for=&quot;todo of todoList&quot; :key=&quot;todo.id&quot; xs8 class=&quot;my-1&quot;&gt;       &lt;todo-item :todo=&quot;todo&quot; @delete=&quot;deleteTodo&quot; \/&gt;     &lt;\/v-flex&gt;   &lt;\/v-layout&gt; &lt;\/template&gt;  &lt;script&gt; import NewTodoForm from '..\/components\/NewTodoForm' import TodoItem from '..\/components\/TodoItem' export default {   components: { TodoItem, NewTodoForm },   data() {     return {       todoList: [         {           id: 1,           title: 'TODO 1',           text:             'Lorem ipsum dolor sit amet, consectetur adipiscing elit',           dueDate: '2020-10-16',           createdDate: '2020-03-09',           done: false,           category: '\u0420\u0430\u0431\u043e\u0442\u0430'         },         {           id: 2,           title: 'TODO 2',           text:             'Lorem ipsum dolor sit amet, consectetur adipiscing elit',           dueDate: '2020-10-16',           createdDate: '2020-03-09',           done: false,           category: '\u0420\u0430\u0431\u043e\u0442\u0430'         },         {           id: 3,           title: 'TODO 3',           text:             'Lorem ipsum dolor sit amet, consectetur adipiscing elit',           dueDate: '2020-10-16',           createdDate: '2020-03-09',           done: false,           category: '\u0420\u0430\u0431\u043e\u0442\u0430'         },         {           id: 4,           title: 'TODO 4',           text:             'Lorem ipsum dolor sit amet, consectetur adipiscing elit',           dueDate: '2020-10-16',           createdDate: '2020-03-09',           done: false,           category: '\u0420\u0430\u0431\u043e\u0442\u0430'         },         {           id: 5,           title: 'TODO 5',           text:             'Lorem ipsum dolor sit amet, consectetur adipiscing elit',           dueDate: '2020-10-16',           createdDate: '2020-03-09',           done: false,           category: '\u0420\u0430\u0431\u043e\u0442\u0430'         },         {           id: 6,           title: 'TODO 6',           text:             'Lorem ipsum dolor sit amet, consectetur adipiscing elit',           dueDate: '2020-10-16',           createdDate: '2020-03-09',           done: false,           category: '\u0420\u0430\u0431\u043e\u0442\u0430'         }       ]     }   },   methods: {     addTodo(newTodo) {       const id = this.todoList.length         ? Math.max.apply(             null,             this.todoList.map(item =&gt; item.id)           ) + 1         : 1       this.todoList.unshift({         id,         createdDate: new Date().toISOString().substr(0, 10),         done: false,         ...newTodo       })     },     deleteTodo(todoId) {       this.todoList = this.todoList.filter(item =&gt; item.id !== todoId)     }   } } &lt;\/script&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u043d\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0435\u0433\u043e\u0441\u044f \u043c\u0430\u043a\u0435\u0442\u0430. \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 <code>dev<\/code> \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043d\u0430 <a href=\"http:\/\/localhost:3000\/\">http:\/\/localhost:3000\/<\/a>, \u0442\u0430\u043c \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u043a\u0435\u0442<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/gs\/g0\/pl\/gsg0plu-vg6tllgm1gvgfcot9oi.png\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h2 id=\"obedinenie-frontenda-i-bekenda\">\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u0438 \u0431\u044d\u043a\u0435\u043d\u0434\u0430<\/h2>\n<p>  <\/p>\n<h3 id=\"nastroyka-csrf-zaschity-django--apollo\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 CSRF-\u0437\u0430\u0449\u0438\u0442\u044b Django + Apollo<\/h3>\n<p>  <\/p>\n<p>\u0412 Django \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/ru.wikipedia.org\/wiki\/\u041c\u0435\u0436\u0441\u0430\u0439\u0442\u043e\u0432\u0430\u044f_\u043f\u043e\u0434\u0434\u0435\u043b\u043a\u0430_\u0437\u0430\u043f\u0440\u043e\u0441\u0430\">CSRF<\/a> \u0437\u0430\u0449\u0438\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u042d\u0442\u0430 \u0437\u0430\u0449\u0438\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <a href=\"https:\/\/djbook.ru\/rel1.7\/topics\/http\/middleware.html\">\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f<\/a> (middleware) \u2014 <code>CsrfViewMiddleware<\/code>. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u043d\u0435\u0433\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>settings.py<\/code> \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>MIDDLEWARE<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442: \u0443 \u043b\u044e\u0431\u043e\u0433\u043e POST-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a Django \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c\u0441\u044f CSRF-\u0442\u043e\u043a\u0435\u043d. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043a\u043b\u043e\u043d\u044f\u0435\u0442 \u044d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<p>  <\/p>\n<p>CSRF-\u0442\u043e\u043a\u0435\u043d \u0432 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u043c django \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043b\u044e\u0431\u044b\u043c GET-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0444\u043e\u0440\u043c\u044b \u043f\u0440\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430.<\/p>\n<p>  <\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432 Apollo \u043c\u0443\u0442\u0430\u0446\u0438\u044f \u0438\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441, \u043c\u0435\u0442\u043e\u0434 \u0438\u0445 \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 POST. Apollo \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u044f <code>Query<\/code> \u043c\u0435\u0442\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u044b\u043b GET, \u0430 \u0434\u043b\u044f <code>Mutation<\/code> \u2014 POST, \u043d\u043e \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044f \u0437\u043d\u0430\u044e, graphene \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u0440\u0435\u0436\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u044b. <\/p>\n<p>  <\/p>\n<p>\u042f \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c: \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u043b \u043b\u043e\u0433\u0438\u043a\u0443 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e <code>CsrfViewMiddleware<\/code> \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b \u0442\u0438\u043f GraphQL \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0438 \u0443\u0436\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b \u0438\u043b\u0438 \u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043b \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 CSRF, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u043d\u0430\u043c \u0444\u0430\u0439\u043b <code>api.py<\/code><\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">api.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># backend\/backend\/api.py import json import graphene from django.middleware.csrf import CsrfViewMiddleware  from backend.todo_list.schema import Query, Mutation  schema = graphene.Schema(query=Query, mutation=Mutation)  class CustomCsrfMiddleware(CsrfViewMiddleware):     def process_view(self, request, callback, callback_args, callback_kwargs):         if getattr(request, 'csrf_processing_done', False):             return None         if getattr(callback, 'csrf_exempt', False):             return None         try:             body = request.body.decode('utf-8')             body = json.loads(body)         # \u0432 \u043b\u044e\u0431\u043e\u0439 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443 CsrfViewMiddleware         except (TypeError, ValueError, UnicodeDecodeError):             return super(CustomCsrfMiddleware, self).process_view(request, callback, callback_args, callback_kwargs)         # \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 list, \u0442.\u043a. \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c &quot;\u0431\u0430\u0442\u0447\u0435\u043d\u043d\u044b\u0435&quot; \u0437\u0430\u043f\u0440\u043e\u0441\u044b         # https:\/\/blog.apollographql.com\/batching-client-graphql-queries-a685f5bcd41b         if isinstance(body, list):             for query in body:                 # \u0435\u0441\u043b\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0435\u0441\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u0430 \u043c\u0443\u0442\u0430\u0446\u0438\u044f, \u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441                 # \u043a \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443 CsrfViewMiddleware                 if 'mutation' in query:                     break             else:                 return self._accept(request)         else:             # \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u043b\u044e\u0431\u044b\u0435 query \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 csrf             if 'query' in body and 'mutation' not in body:                 return self._accept(request)         return super(CustomCsrfMiddleware, self).process_view(request, callback, callback_args, callback_kwargs)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u0432 \u0444\u0430\u0439\u043b\u0435 <code>settings.py<\/code> \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c &quot;\u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439&quot; <code>CsrfViewMiddleware<\/code>, \u043d\u0430 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># settings.py MIDDLEWARE = [     ...,     'backend.backend.api.CustomCsrfMiddleware',     # 'django.middleware.csrf.CsrfViewMiddleware',     ..., ]<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0443\u0432\u0430\u0436\u0430\u0435\u043c\u044b\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0437\u043d\u0430\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0435 \u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b CSRF-\u0437\u0430\u0449\u0438\u0442\u044b \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 Django + Nuxt + Apollo, \u0442\u043e \u043f\u0440\u0438\u0437\u044b\u0432\u0430\u044e \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c \u0437\u043d\u0430\u043d\u0438\u0435\u043c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445.<\/p>\n<p>  <\/p>\n<h3 id=\"django-cors-headers\">Django CORS Headers<\/h3>\n<p>  <\/p>\n<p>\u0422.\u043a. dev \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u0438 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0443 \u043d\u0430\u0441 \u0441\u0442\u043e\u044f\u0442 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u0440\u0442\u0430\u0445, \u0442\u043e Django \u043d\u0443\u0436\u043d\u043e \u043e\u043f\u043e\u0432\u0435\u0441\u0442\u0438\u0442\u044c, \u0441 \u043a\u0430\u043a\u0438\u0445 \u0445\u043e\u0441\u0442\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0442\u044c\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0435\u043c\u0443 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c. \u0410 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0432 \u044d\u0442\u043e\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <code>django-cors-headers<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">pipenv install &quot;django-cors-headers&gt;=3.2&quot;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 <code>settings.py<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c: <\/p>\n<p>  <\/p>\n<pre><code class=\"python\"># backend\/backend\/settings.py from corsheaders.defaults import default_headers  INSTALLED_APPS = [     ...,     'graphene_django',     'backend.todo_list',     'corsheaders',  # \u0432\u043e\u0442 \u044d\u0442\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 ]  CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_HEADERS = default_headers + ('cache-control', 'cookies') CORS_ORIGIN_ALLOW_ALL = True  # \u043d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f production  # \u0410 \u0442\u0430\u043a\u0436\u0435 \u043f\u0430\u0440\u043e\u0447\u043a\u0443 middleware MIDDLEWARE = [     ...,     'corsheaders.middleware.CorsMiddleware',     'django.middleware.common.CommonMiddleware',     ..., ]<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"ustanovka-i-nastroyka-apollo\">\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Apollo<\/h3>\n<p>  <\/p>\n<p>\u0414\u043b\u044f Nuxt \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c <code>apollo<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 <code>vue-apollo<\/code> (\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 Apollo). \u0414\u043b\u044f \u0435\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npm install --save @nuxtjs\/apollo graphql-tag cookie-universal-nuxt<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>Apollo<\/code> \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <code>cookie-universal-nuxt<\/code> \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u043a\u0443\u043a\u0430\u043c\u0438 \u043f\u0440\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0435 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<br \/>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u044d\u0442\u0438 \u043c\u043e\u0434\u0443\u043b\u0438 \u0432 <code>nuxt.config.js<\/code>. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0435\u0439 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0442\u0430\u043c \u0443\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0441\u043e\u043a\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0443\u043b\u0435\u0439. \u041a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0442\u0430\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c <code>vuetify<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ nuxt.config.js export default {   ...,   modules: [     ...,     '@nuxtjs\/vuetify',     '@nuxtjs\/apollo',     'cookie-universal-nuxt'   ],   apollo: {     clientConfigs: {       default: '~\/plugins\/apollo-client.js'     }   },   ... }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Apollo \u0434\u0435\u043b\u043e \u043d\u0435\u0432\u0441\u0435\u0433\u0434\u0430 \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0435. \u041f\u043e\u0441\u0442\u0430\u0440\u0430\u0435\u043c\u0441\u044f \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 \u0432\u044b\u0448\u0435 \u043f\u0443\u0442\u0438:<\/p>\n<p>  <\/p>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442 <code>Apollo<\/code>, \u0430 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043c \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">apollo-client.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">\/\/ frontend\/plugins\/apollo-client.js import { HttpLink } from 'apollo-link-http' import { setContext } from 'apollo-link-context' import { from, concat } from 'apollo-link' import { InMemoryCache } from 'apollo-cache-inmemory'  \/\/ \u0415\u0441\u043b\u0438 \u043f\u043b\u0430\u0433\u0438\u043d \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439, \u0442\u043e \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Nuxt \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0432 \u043d\u0435\u0451 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 ctx export default ctx =&gt; {   \/**    * \u041f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0435 \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438    * \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a \u0431\u044d\u043a\u0435\u043d\u0434\u0443 \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f, \u0442\u0430\u043a \u0447\u0442\u043e &quot;\u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c&quot;    * \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.    *\/   const ssrMiddleware = setContext((_, { headers }) =&gt; {     if (process.client) return headers     return {       headers: {         ...headers,         connection: ctx.app.context.req.headers.connection,         referer: ctx.app.context.req.headers.referer,         cookie: ctx.app.context.req.headers.cookie       }     }   })    \/**    * \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 CSRF-\u0442\u043e\u043a\u0435\u043d\u0430 \u043a \u0437\u0430\u043f\u0440\u043e\u0441\u0443.    * https:\/\/docs.djangoproject.com\/en\/2.2\/ref\/csrf\/#ajax    *\/   const csrfMiddleware = setContext((_, { headers }) =&gt; {     return {       headers: {         ...headers,         'X-CSRFToken': ctx.app.$cookies.get('csrftoken') || null       }     }   })   const httpLink = new HttpLink({     uri: 'http:\/\/localhost:8000\/graphql\/',     credentials: 'include'   })   \/\/ Middleware \u0432 Apollo \u044d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u043e\u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0447\u0442\u043e \u0438 middleware \u0432 Django,    \/\/ \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430. \u041e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0438\u0445 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0443. \u041f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u0430\u0436\u043d\u0430.   const link = from([csrfMiddleware, ssrMiddleware, httpLink])   \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043a\u044d\u0448. \u041f\u0440\u0438 \u0434\u043e\u043b\u0436\u043d\u043e\u043c \u0443\u0441\u0435\u0440\u0434\u0438\u0438 \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c Vuex,   \/\/ \u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u043a\u0430\u043a-\u043d\u0438\u0431\u0443\u0434\u044c \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u0440\u0430\u0437   const cache = new InMemoryCache()    return {     link,     cache,     \/\/ \u0431\u0435\u0437 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e apollo-module HttpLink'a \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0441\u044b\u043f\u044f\u0442\u0441\u044f \u0432\u0430\u0440\u043d\u0438\u043d\u0433\u0438     defaultHttpLink: false   } }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043b\u0443\u0447\u0448\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437 \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e Nuxt \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 dev \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<p>  <\/p>\n<h3 id=\"ozhivlyaem-prilozhenie\">\u041e\u0436\u0438\u0432\u043b\u044f\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u0418 \u0432\u043e\u0442 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0444\u0440\u043e\u043d\u0442 \u0438 \u0431\u044d\u043a.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u043a \u0431\u044d\u043a\u0435\u043d\u0434\u0443. \u0412 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u043b\u0441\u044f \u043f\u043e \u043f\u0443\u0442\u0438 <code>frontend\/graphql.js<\/code> \u0441 \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c \u043d\u0430\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">graphql.js<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"javascript\">import gql from 'graphql-tag'  \/\/ \u0442.\u043a. \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u043f\u0438\u0441\u0438 Todo \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u043e \u0432\u0441\u0435\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445, \/\/ \u0442\u043e \u0440\u0435\u0437\u043e\u043d\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0438\u0445 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \/\/ https:\/\/www.apollographql.com\/docs\/react\/data\/fragments\/ const TODO_FRAGMENT = gql`   fragment TodoContents on TodoNode {     id     title     text     done     createdDate     dueDate     category {       id       name     }   } `  const ADD_TODO = gql`   mutation(     $title: String!     $text: String     $dueDate: Date!     $category: String!   ) {     addTodo(       title: $title       text: $text       dueDate: $dueDate       category: $category     ) {       ...TodoContents     }   }   ${TODO_FRAGMENT} `  const TOGGLE_TODO = gql`   mutation($todoId: ID) {     toggleTodo(todoId: $todoId) {       ...TodoContents     }   }   ${TODO_FRAGMENT} `  const GET_CATEGORIES = gql`   {     categories {       id       name     }   } `  const GET_TODO_LIST = gql`   {     todoList {       ...TodoContents     }   }   ${TODO_FRAGMENT} `  const REMOVE_TODO = gql`   mutation($todoId: ID) {     removeTodo(todoId: $todoId)   } `  export { ADD_TODO, TOGGLE_TODO, GET_CATEGORIES, GET_TODO_LIST, REMOVE_TODO }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430. \u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0443\u0434\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u0431\u044d\u043a\u0435\u043d\u0434\u043e\u043c.<\/p>\n<p>  <\/p>\n<p>\u0418\u0437\u043c\u0435\u043d\u0438\u043c Vue \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">index.vue<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!-- frontend\/pages\/index.vue --&gt; &lt;template&gt;   &lt;v-layout row wrap justify-center&gt;     &lt;v-flex xs8 class=&quot;pb-1&quot;&gt;       &lt;!-- emit'\u044b \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u044b --&gt;       &lt;new-todo-form \/&gt;     &lt;\/v-flex&gt;     &lt;v-flex v-for=&quot;todo of todoList&quot; :key=&quot;todo.id&quot; xs8 class=&quot;my-1&quot;&gt;       &lt;todo-item :todo=&quot;todo&quot; \/&gt;     &lt;\/v-flex&gt;   &lt;\/v-layout&gt; &lt;\/template&gt;  &lt;script&gt; import NewTodoForm from '..\/components\/NewTodoForm' import TodoItem from '..\/components\/TodoItem' \/\/ \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0432\u0435\u0436\u0435\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b import { GET_TODO_LIST } from '..\/graphql'  export default {   components: { TodoItem, NewTodoForm },   data() {     return {       todoList: []     }   },   apollo: {     \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a todoList. \u041f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f todoList     \/\/ \u0434\u043e\u043b\u0436\u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043e\u0434\u043d\u0430\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f     \/\/ \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439     todoList: { query: GET_TODO_LIST }   } } &lt;\/script&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">NewTodoForm.vue<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!-- frontend\/components\/NewTodoForm.vue --&gt; &lt;template&gt;   &lt;v-form ref=&quot;form&quot; v-model=&quot;valid&quot;&gt;     &lt;v-card&gt;       &lt;v-card-text class=&quot;pt-0 mt-0&quot;&gt;         &lt;v-layout row wrap&gt;           &lt;v-flex xs8&gt;             &lt;v-text-field               v-model=&quot;newTodo.title&quot;               :rules=&quot;[nonEmptyField]&quot;               label=&quot;\u0417\u0430\u0434\u0430\u0447\u0430&quot;               prepend-icon=&quot;check_circle_outline&quot;             \/&gt;           &lt;\/v-flex&gt;           &lt;v-flex xs4&gt;             &lt;v-menu               ref=&quot;menu&quot;               v-model=&quot;menu&quot;               :close-on-content-click=&quot;false&quot;               :nudge-right=&quot;40&quot;               :return-value.sync=&quot;newTodo.dueDate&quot;               lazy               transition=&quot;scale-transition&quot;               offset-y               full-width               min-width=&quot;290px&quot;             &gt;               &lt;template v-slot:activator=&quot;{ on }&quot;&gt;                 &lt;v-text-field                   v-model=&quot;newTodo.dueDate&quot;                   :rules=&quot;[nonEmptyField]&quot;                   v-on=&quot;on&quot;                   label=&quot;\u0414\u0430\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f&quot;                   prepend-icon=&quot;event&quot;                   readonly                 \/&gt;               &lt;\/template&gt;               &lt;v-date-picker                 v-model=&quot;newTodo.dueDate&quot;                 no-title                 scrollable                 locale=&quot;ru-ru&quot;                 first-day-of-week=&quot;1&quot;               &gt;                 &lt;v-spacer \/&gt;                 &lt;v-btn @click=&quot;menu = false&quot; flat color=&quot;primary&quot;&gt;\u041e\u0442\u043c\u0435\u043d\u0430&lt;\/v-btn&gt;                 &lt;v-btn                   @click=&quot;$refs.menu.save(newTodo.dueDate)&quot;                   flat                   color=&quot;primary&quot;                   &gt;\u0412\u044b\u0431\u0440\u0430\u0442\u044c&lt;\/v-btn                 &gt;               &lt;\/v-date-picker&gt;             &lt;\/v-menu&gt;           &lt;\/v-flex&gt;           &lt;v-flex xs12&gt;             &lt;v-textarea               v-model=&quot;newTodo.text&quot;               :rules=&quot;[nonEmptyField]&quot;               label=&quot;\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435&quot;               prepend-icon=&quot;description&quot;               hide-details               rows=&quot;1&quot;               class=&quot;py-0 my-0&quot;             \/&gt;           &lt;\/v-flex&gt;         &lt;\/v-layout&gt;       &lt;\/v-card-text&gt;       &lt;v-card-actions&gt;         &lt;v-combobox           v-model=&quot;newTodo.category&quot;           :rules=&quot;[nonEmptyField]&quot;           :items=&quot;categories&quot;           hide-details           label=&quot;\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f&quot;           class=&quot;my-0 mx-2 mb-2 pt-0&quot;           prepend-icon=&quot;category&quot;         \/&gt;         &lt;v-spacer \/&gt;         &lt;v-btn           :disabled=&quot;!valid&quot;           :loading=&quot;loading&quot;           @click=&quot;add&quot;           color=&quot;blue lighten-1&quot;           flat           &gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c&lt;\/v-btn         &gt;       &lt;\/v-card-actions&gt;     &lt;\/v-card&gt;   &lt;\/v-form&gt; &lt;\/template&gt;  &lt;script&gt; \/\/ \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0432\u0435\u0436\u0435\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b import { ADD_TODO, GET_CATEGORIES, GET_TODO_LIST } from '..\/graphql'  export default {   name: 'NewTodoForm',   data() {     return {       newTodo: null,       categories: [],       valid: false,       menu: false,       nonEmptyField: text =&gt;         text ? !!text.length : '\u041f\u043e\u043b\u0435 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043f\u0443\u0441\u0442\u044b\u043c',       loading: false \/\/ \u0438\u043d\u0434\u0438\u043a\u0430\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430     }   },   apollo: {     \/\/ \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439     categories: {       query: GET_CATEGORIES,       update({ categories }) {         return categories.map(c =&gt; c.name)       }     }   },   created() {     this.clear()   },   methods: {     add() {       this.loading = true       this.$apollo         .mutate({           mutation: ADD_TODO,           variables: {             ...this.newTodo           },           \/\/ \u043a\u044d\u0448 \u0430\u043f\u043e\u043b\u043b\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043a\u044d\u0448\u0430, \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438           \/\/ \u043e\u0442 \u0442\u043e\u0433\u043e, \u0432 \u043a\u0430\u043a\u043e\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u0434. \u0417\u0434\u0435\u0441\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0442\u0432\u0435\u0442\u0430           \/\/ \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c Todo. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0451 \u0432 \u043a\u044d\u0448, \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c           \/\/ \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443 GET_TODO_LIST, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f Apollo           \/\/ \u0441\u0430\u043c \u0440\u0430\u0437\u043e\u0448\u043b\u0435\u0442 \u0432\u0441\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0412 \u043d\u0430\u0448\u0435\u043c           \/\/ \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f todoList \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 index.vue           update: (store, { data: { addTodo } }) =&gt; {             \/\/ \u0435\u0441\u043b\u0438 \u0432 \u043a\u044d\u0448\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0443, \u0442\u043e \u0431\u0440\u043e\u0441\u0438\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435             const todoListData = store.readQuery({ query: GET_TODO_LIST })             todoListData.todoList.unshift(addTodo)             store.writeQuery({ query: GET_CATEGORIES, data: todoListData })              const categoriesData = store.readQuery({ query: GET_CATEGORIES })             \/\/ \u0412 \u0441\u043f\u0438\u0441\u043a\u0435 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439 \u0438\u0449\u0435\u043c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e \u043d\u043e\u0432\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Todo. \u041f\u0440\u0438 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e\u043c \u043f\u043e\u0438\u0441\u043a\u0435             \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043a\u044d\u0448. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439 \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f             \/\/ \u0432 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438             const category = categoriesData.categories.find(               c =&gt; c.name === addTodo.category.name             )             if (!category) {               categoriesData.categories.push(addTodo.category)               store.writeQuery({ query: GET_CATEGORIES, data: categoriesData })             }           }         })         .then(() =&gt; {           this.clear()           this.loading = false           this.$refs.form.reset() \/\/ \u0441\u0431\u0440\u043e\u0441 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0444\u043e\u0440\u043c\u044b         })     },     clear() {       this.newTodo = {         title: '',         text: '',         dueDate: '',         category: ''       }     }   } } &lt;\/script&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">TodoItem.vue<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!-- frontend\/components\/NewTodoForm.vue --&gt; &lt;template&gt;   &lt;v-card&gt;     &lt;v-card-title class=&quot;pb-1&quot; style=&quot;overflow-wrap: break-word;&quot;&gt;       &lt;b&gt;{{ todo.title }}&lt;\/b&gt;       &lt;v-spacer \/&gt;       &lt;!-- \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 --&gt;       &lt;v-btn         @click=&quot;remove&quot;         flat         small         icon         style=&quot;position: absolute; right: 0; top: 0&quot;       &gt;         &lt;v-icon :disabled=&quot;$nuxt.isServer&quot; small&gt;close&lt;\/v-icon&gt;       &lt;\/v-btn&gt;     &lt;\/v-card-title&gt;     &lt;v-card-text class=&quot;py-1&quot;&gt;       &lt;v-layout row justyfy-center align-center&gt;         &lt;v-flex xs11 style=&quot;overflow-wrap: break-word;&quot;&gt;           {{ todo.text }}         &lt;\/v-flex&gt;         &lt;v-flex xs1&gt;           &lt;div style=&quot;text-align: right;&quot;&gt;             &lt;!-- \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043b\u0438\u043a\u0430 --&gt;             &lt;v-checkbox               :value=&quot;todo.done&quot;               @click.once=&quot;toggle&quot;               hide-details               class=&quot;pa-0 ma-0&quot;               style=&quot;display: inline-block;&quot;               color=&quot;green lighten-1&quot;             \/&gt;           &lt;\/div&gt;         &lt;\/v-flex&gt;       &lt;\/v-layout&gt;     &lt;\/v-card-text&gt;     &lt;v-card-actions&gt;       &lt;span class=&quot;grey--text&quot;&gt;         \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u043e &lt;v-icon small&gt;event&lt;\/v-icon&gt; {{ todo.dueDate }} | \u0421\u043e\u0437\u0434\u0430\u043d\u043e         &lt;v-icon small&gt;calendar_today&lt;\/v-icon&gt; {{ todo.createdDate }}       &lt;\/span&gt;       &lt;v-spacer \/&gt;       &lt;span class=&quot;grey--text&quot;&gt;         &lt;!-- \u0418\u0437\u043c\u0435\u043d\u0435\u043d \u043f\u0443\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u043d\u0438 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 --&gt;         &lt;v-icon small&gt;category&lt;\/v-icon&gt;\u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f: {{ todo.category.name }}       &lt;\/span&gt;     &lt;\/v-card-actions&gt;   &lt;\/v-card&gt; &lt;\/template&gt;  &lt;script&gt; \/\/ \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0432\u0435\u0436\u0435\u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b import { GET_TODO_LIST, REMOVE_TODO, TOGGLE_TODO } from '..\/graphql'  export default {   name: 'TodoItem',   props: {     todo: {       type: Object,       default: () =&gt; ({})     }   },   \/\/ \u0441 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e-\u0441\u0435\u0440\u044c\u0435\u0437\u043d\u0435\u0435   methods: {     toggle() {       \/\/ \u0414\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e       \/\/ \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e update. Apollo \u0441\u0430\u043c \u043d\u0430\u0439\u0434\u0451\u0442 \u0432 \u043a\u0430\u043a\u0438\u0445       \/\/ \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 &quot;\u0443\u0447\u0430\u0441\u0442\u0432\u0443\u0435\u0442&quot; \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c, \u0438 \u0440\u0430\u0437\u043e\u0448\u043b\u0435\u0442 \u0432\u0441\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c       \/\/ \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 index.vue       \/\/ \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 Todo       this.$apollo.mutate({         mutation: TOGGLE_TODO,         variables: {           todoId: this.todo.id         }       })     },     remove() {       \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f update \u043d\u0435 \u0432\u0438\u0434\u0438\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 this       const todoId = this.todo.id       this.$apollo.mutate({         mutation: REMOVE_TODO,         variables: {           todoId         },         update(store, { data: { removeTodo } }) {           if (!removeTodo) return           \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u0437 \u043a\u044d\u0448\u0430           const data = store.readQuery({ query: GET_TODO_LIST })           data.todoList = data.todoList.filter(todo =&gt; todo.id !== todoId)           \/\/ \u0421\u0430\u043c\u043e\u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0430\u0435\u043c\u0441\u044f!           store.writeQuery({ query: GET_TODO_LIST, data })         }       })     }   } } &lt;\/script&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/b><\/p>\n<div class=\"spoiler_text\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xy\/3e\/_-\/xy3e_-efabaavt-hjfy68fb_ftw.gif\"\/><\/p>\n<\/div>\n<\/div>\n<p>  <\/p>\n<h2 id=\"zaklyuchenie\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u0430\u043a \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 Django \u0438 Nuxt \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GraphQL API, \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0434\u043e\u0432\u0435\u043b\u043e\u0441\u044c \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043c\u043d\u0435. \u041d\u0430\u0434\u0435\u044e\u0441\u044c \u044d\u0442\u043e \u043f\u043e\u0434\u0442\u043e\u043b\u043a\u043d\u0435\u0442 \u044d\u043d\u0442\u0443\u0437\u0438\u0430\u0441\u0442\u043e\u0432 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043d\u043e\u0432\u043e\u0435, \u0438 \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u044f \u0432 \u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. <\/p>\n<p>  <\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/github.com\/IngvarListard\/nuxt-django-graphql-example\">GitHub<\/a>.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/492486\/\"> https:\/\/habr.com\/ru\/post\/492486\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/492486\/\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/cm\/nl\/wm\/cmnlwmcwqu2drhdusjqe2nn6luq.jpeg\"\/><\/p>\n<p>  <\/p>\n<h2 id=\"predislovie\">\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>  <\/p>\n<p><strong>Nuxt<\/strong> \u2014 &quot;\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430\u0434 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c Vue&quot; \u0438\u043b\u0438 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Vue-based \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043b\u0443\u0447\u0448\u0438\u0445 \u043f\u0440\u0430\u043a\u0442\u0438\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 Vue. \u0421\u0440\u0435\u0434\u0438 \u043d\u0438\u0445: \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f; \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u0435\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0432\u0438\u0434\u0435 Nuxt \u043c\u043e\u0434\u0443\u043b\u0435\u0439; \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/vuex.vuejs.org\/ru\/\">Vuex<\/a> \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u043b\u044e\u0431\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e; \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0438 \u043f\u0440\u0435\u0434\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 <a href=\"https:\/\/ssr.vuejs.org\/ru\/#%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%BD%D1%8B%D0%B9-%D1%80%D0%B5%D0%BD%D0%B4%D0%B5%D1%80%D0%B8%D0%BD%D0%B3-ssr\">SSR<\/a> \u0441 <a href=\"https:\/\/vue-loader-v14.vuejs.org\/ru\/features\/hot-reload.html\">hot-reloading&#8217;\u043e\u043c<\/a><\/p>\n<p>  <\/p>\n<p><strong>Django<\/strong> \u2014 \u0441\u0430\u043c\u044b\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 \u043f\u043e\u0447\u0442\u0438 \u0441\u0430\u043c\u043e\u043c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u2014 Python. \u0421\u0430\u043c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u0443\u044e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442 \u043a\u0430\u043a &quot;\u0412\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u043f\u0435\u0440\u0444\u0435\u043a\u0446\u0438\u043e\u043d\u0438\u0441\u0442\u043e\u0432 \u0441 \u0434\u0435\u0434\u043b\u0430\u0439\u043d\u0430\u043c\u0438&quot;. \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435 &quot;\u0432\u0441\u0451 \u0432 \u043e\u0434\u043d\u043e\u043c&quot; \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u043a\u0440\u0430\u0442\u0447\u0430\u0439\u0448\u0438\u0435 \u0441\u0440\u043e\u043a\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c MVP \u0432\u0430\u0448\u0435\u0433\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p><strong>GraphQL<\/strong> \u2014 \u044f\u0437\u044b\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0435\u0439 Facebook. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u0442 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c\u0441\u044f \u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u0445 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u044d\u0442\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a <strong>Apollo<\/strong> \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430 \u0438 <strong>graphene<\/strong> \u0434\u043b\u044f \u0431\u044d\u043a\u0435\u043d\u0434\u0430.<\/p>\n<p>  <\/p>\n<h2 id=\"o-chem-i-dlya-kogo-eta-statya\">\u041e \u0447\u0435\u043c \u0438 \u0434\u043b\u044f \u043a\u043e\u0433\u043e \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f<\/h2>\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-300174","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/300174","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=300174"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/300174\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=300174"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=300174"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=300174"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}