{"id":371026,"date":"2024-05-21T04:38:53","date_gmt":"2024-05-21T04:38:53","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=371026"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=371026","title":{"rendered":"<span>\u0412\u0430\u043b\u0438\u0434\u0438\u0440\u0443\u0439\u0442\u0435 \u044d\u0442\u043e \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 (\u0442\u0435\u043f\u0435\u0440\u044c \u0443\u0436 \u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u043e\u0439):<\/p>\n<pre><code class=\"python\">def handler_create_user(r: Request):     input_data = r.post()     first_name, email = input_data.get('firstName'), input_data.get('email')     if not first_name or not email:         raise HTTPBadRequest('name &amp; email must have values')     return User.create(name=first_name, email=email, password=uuid4())<\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u043a\u0430\u043a\u0438\u0435 \u0442\u0443\u0442 \u0435\u0441\u0442\u044c \u0443\u0437\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430?<\/p>\n<ul>\n<li>\n<p>\u041c\u044b \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u043d\u0435 \u0438\u043c\u0435\u0435\u043c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043a\u0430\u043a\u0438\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u043a\u043b\u044e\u0447\u0438), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043e\u0441\u0442\u0430\u0435\u043c, \u043d\u0430\u0434\u0435\u044f\u0441\u044c \u043d\u0430 \u0443\u0441\u043f\u0435\u0445, \u0447\u0435\u0440\u0435\u0437 <code>get<\/code>, \u0430 \u043f\u043e\u0442\u043e\u043c \u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0447\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0451 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u043e\u0435<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044f \u0441\u0442\u0438\u043b\u0435\u0439 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 (Snake case, Camel case, etc.) \u0442\u043e\u0436\u0435 \u043b\u043e\u0436\u0438\u0442\u0441\u044f \u043d\u0430 \u0445\u0440\u0443\u043f\u043a\u0438\u0435 \u043f\u043b\u0435\u0447\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0442.\u043e. \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u0432\u0438\u0434\u0430 <code>my_var = input_data.get('my_var')<\/code> \u043c\u043e\u0433\u0443\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u201c\u0437\u0430\u0433\u0440\u044f\u0437\u043d\u0438\u0442\u044c\u201d \u043a\u043e\u0434<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0442\u0443\u0442 \u0436\u0435 (\u0432 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0435), \u0438 \u043e\u043d\u0430 \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u043e\u0439<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u044f\u0432\u043d\u043e \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u0432 (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2013 \u043e\u0442 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445). \u0422.\u043e. \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0432 \u043c\u043e\u0434\u0435\u043b\u044c, \u043e\u043d\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u0438 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0441\u043b\u043e\u043c\u0430\u0442\u044c API<\/p>\n<\/li>\n<li>\n<p>\u0412 response \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u043d\u0435\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0430\u0440\u043e\u043b\u044c \u0438\u043b\u0438 \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447)<\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u043e\u0436\u043d\u043e \u043b\u0438 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u0443\u0436\u0435? \u041a\u043e\u043d\u0435\u0447\u043d\u043e!<\/p>\n<pre><code class=\"python\">def handler_create_user(r: Request):     return User.create(**r.post(), password=uuid4())<\/code><\/pre>\n<p>\u0410 \u0432\u043e\u0442 \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043b\u0443\u0447\u0448\u0435, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h2>\u041a\u0430\u043a \u044d\u0442\u043e \u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c<\/h2>\n<p>\u0421\u0440\u0430\u0437\u0443 \u043e\u0433\u043e\u0432\u043e\u0440\u044e\u0441\u044c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0430\u0437\u0440\u0435\u0437\u0435 \u0440\u0430\u0431\u043e\u0442\u044b API \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0434\u043b\u044f desktop \u0441\u0438\u0441\u0442\u0435\u043c \u043f\u043e\u0434\u0445\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0438\u043d\u044b\u043c.<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u0442\u044c \u0441\u043b\u0443\u0447\u0430\u0438, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043d\u0435 \u043d\u0443\u0436\u043d\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b \u0441\u0442\u0430\u0440\u0442\u0430\u043f, \u0441\u0440\u043e\u043a \u0436\u0438\u0437\u043d\u0438 \u043a\u043e\u0434\u0430 \u2013 \u043e\u0434\u043d\u0430 \u043d\u0435\u0434\u0435\u043b\u044f, \u043d\u0435\u043a\u043e\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u0430\u0434\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u043e<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u2013 \u044d\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0442\u043e\u0438\u0442 \u043b\u0438\u0448\u044c \u043d\u0430 \u0441\u0442\u044b\u043a\u0435 \u0441\u0438\u0441\u0442\u0435\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0438\u0448\u043b\u043e \u0438\u0437\u0432\u043d\u0435, \u0430 \u0434\u0430\u043b\u0435\u0435, \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043c\u044b \u0441\u0430\u043c\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435. \u041c\u043e\u0436\u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u0434\u0443\u043c\u0430\u0442\u044c \u043a\u0430\u043a \u043e \u043d\u0435\u043a\u043e\u0439 \u0433\u0440\u0430\u043d\u0438\u0446\u0435, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442, \u0430 \u0434\u0430\u043b\u0435\u0435 \u043d\u0438\u043a\u0442\u043e \u043f\u0430\u0441\u043f\u043e\u0440\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 (\u0434\u0430 \u0438 \u043d\u0435 \u043d\u0430\u0434\u043e, \u0432\u0435\u0434\u044c \u0432\u0441\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0436\u0435 \u043f\u043e\u0434 \u043d\u0430\u0448\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u043c)<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0447\u0435\u043c, \u044d\u0442\u0443 \u0433\u0440\u0430\u043d\u0438\u0446\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u043a\u0430\u043a \u043f\u043e \u201c\u043f\u0440\u0438\u0435\u0437\u0434\u0435\u201d, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438 \u201c\u043e\u0442\u044a\u0435\u0437\u0434\u0435\u201d. \u0412\u0430\u0436\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0445\u043e\u0434, \u043d\u043e \u0438 \u0432\u044b\u0445\u043e\u0434, \u0438\u0431\u043e \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043d\u0435 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 ORM \u043c\u043e\u0434\u0435\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0440\u0443\u0436\u0443, \u0434\u0430 \u0438 \u0441\u0430\u043c\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c, \u0442.\u043a. \u043e\u0442\u0432\u0435\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044d\u0442\u043e \u0434\u0430\u0441\u0442 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u0430\u0448\u0435\u0433\u043e API: \u0447\u0451\u0442\u043a\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043e\u0442\u0432\u0435\u0442\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c\u0441\u044f<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u0442\u044c \u0441 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0435\u0439 (\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c, cast) \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043c\u044b \u0436\u0434\u0451\u043c \u0432 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435 \u0434\u0430\u0442\u0443, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u044f\u0442\u043d\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0447\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0430\u0442\u0430, \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0435\u0449\u0435 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044f <code>str -> datetime<\/code>; \u0438\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u0441\u044f \u0432 <code>enum<\/code><\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0443\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u0441\u0430\u0439\u0442 \u0438\u043b\u0438 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043d\u0430 \u0434\u0432\u0443\u0445 \u0443\u0440\u043e\u0432\u043d\u044f\u0445: \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0444\u0440\u043e\u043d\u0442\u0430 (\u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u0434\u0443\u0440\u0430\u043a\u0430) \u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0431\u0435\u043a\u0430 (\u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u0445\u0430\u043a\u0435\u0440\u0430). \u041f\u043e\u0440\u043e\u0439 \u043f\u0435\u0440\u0432\u044b\u043c \u043f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0433\u0430\u044e\u0442 \u0432 \u0443\u0433\u043e\u0434\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043f\u043e\u043b\u0443\u0447\u0430\u044f \u0431\u043e\u043d\u0443\u0441\u043e\u043c \u0443\u0445\u0443\u0434\u0448\u0435\u043d\u0438\u0435 UX \u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0441\u0435\u0442\u044c; <span class=\"habrahidden\">\u043f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440<\/span>), \u043d\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u2013 \u044d\u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0440\u0443\u0431\u0435\u0436 \u043e\u0431\u043e\u0440\u043e\u043d\u044b, \u0438\u043d\u0430\u0447\u0435 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0432\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u0436\u0434\u0430\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0431\u0430\u0437\u0435, \u0430 \u0432\u044b \u0438\u0445 \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u0434\u0435\u043b\u0430\u0442\u044c<\/p>\n<\/li>\n<li>\n<p>\u0412 MVC-like \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 (view) \u0431\u0443\u0434\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0441\u0442\u044b\u043c, \u0442.\u043a. \u0432\u0441\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0432 \u0441\u0445\u0435\u043c\u0430\u0445. \u0414\u0430 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c \u0443\u0434\u043e\u0431\u043d\u0435\u0435<\/p>\n<\/li>\n<\/ul>\n<h2> Show me the code<\/h2>\n<p>\u0421\u0440\u0430\u0432\u043d\u0438\u043c \u0447\u0435\u0442\u044b\u0440\u0435 Python \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u0438\u043d\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0442\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u0435\u043b\u044f json\u2019\u043e\u0432 (a.k.a. backend developer) \u0430 \u0442\u0430\u043a \u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a. \u0411\u043e\u043d\u0443\u0441\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043d\u0435\u043a\u0443\u044e \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0441\u0432\u0435\u0436\u0438\u0442\u044c \u043f\u0430\u043c\u044f\u0442\u044c \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0411\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430 \u0432\u0445\u043e\u0434 \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0442.\u0435. \u043d\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (request) \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u044d\u0442\u043e\u0442 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0438 \u043a\u0430\u043a \u043f\u043e\u0442\u043e\u043c \u0438\u0437 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0441\u043e\u0437\u0434\u0430\u0441\u0442\u0441\u044f json \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430 (response).<\/p>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0435\u0449\u0451 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0434\u043d\u043e \u0438\u0437 \u043f\u043e\u043b\u0435\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u043e\u043c \u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0435\u0449\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c sql \u0437\u0430\u043f\u0440\u043e\u0441. \u042d\u0442\u043e \u043f\u043e\u0445\u0432\u0430\u043b\u044c\u043d\u043e, \u043d\u043e \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 (dependency) \u0432 \u0441\u0445\u0435\u043c\u044b \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043e\u0442\u043a\u0440\u043e\u0435\u0442 \u043f\u043e\u0440\u0442\u0430\u043b \u0432 \u0430\u0434, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0437\u0434\u043d\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u0432 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043e\u0442\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445.<\/p>\n<h3>Pydantic<\/h3>\n<p>\u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f, \u0442.\u043a. \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0445\u0430\u0439\u043f\u044f\u0449\u0435\u0433\u043e FastApi.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0441\u0445\u0435\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from typing import Annotated, ClassVar, Literal  from pydantic import (     UUID4,     BaseModel,     ConfigDict,     EmailStr,     Field,     HttpUrl,     NonNegativeInt,     PastDatetime,     PositiveInt,     field_validator,     model_validator, ) from pydantic_extra_types.country import CountryAlpha3 from pydantic_extra_types.payment import PaymentCardNumber  from validators.common import Gender   class DocumentSchema(BaseModel):     number: Annotated[int | str, Field(alias='full_number')]   class PydanticSchema(BaseModel):     model_config: ClassVar = ConfigDict(extra='ignore')          schema_version: Literal['3.14.15']     id: UUID4     created_at: PastDatetime     name: Annotated[str, Field(min_length=2, max_length=32)]     age: Annotated[int, Field(ge=0, le=100)]     is_client: bool     gender: Gender     email: EmailStr     social_profile_url: HttpUrl     bank_cards: list[PaymentCardNumber] | None     countries: Annotated[str, Field(min_length=1, max_length=64)]     document: DocumentSchema     page_number: NonNegativeInt     page_size: PositiveInt      @field_validator('age', mode='after')     @classmethod     def check_adults(cls, value: int) -> int:         if value &lt; 18:             raise ValueError('only adults')         return value      @field_validator('countries')     @classmethod     def parse_counties(cls, value: str) -> list[CountryAlpha3]:         return [CountryAlpha3(c) for c in value.split(',')]      @model_validator(mode='before')     @classmethod     def general_check(cls, data: dict) -> dict:         if data.get('is_client') and not data.get('bank_cards'):             raise ValueError('cards are required for clients')         return data<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0443\u0442 \u0432 \u0445\u0432\u043e\u0441\u0442 \u0438 \u0433\u0440\u0438\u0432\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0442\u0438\u043f\u043e\u0432, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u043e\u0434 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u043c \u0438 \u043f\u0440\u0438\u044f\u0442\u043d\u044b\u043c. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0440\u0430\u043d\u044c\u0448\u0435 \u0431\u044b\u043b\u0438 \u0447\u0430\u0441\u0442\u044c\u044e Pydantic, \u043d\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443.<\/p>\n<h3>Marshmallow<\/h3>\n<p>\u0412 \u043c\u043e\u0435\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 aiohttp \u0438\u043b\u0438 Flask.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0441\u0445\u0435\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import typing from datetime import datetime  from marshmallow import (     EXCLUDE,     Schema,     ValidationError,     fields,     validate,     validates,     validates_schema, ) from marshmallow.utils import missing as missing_ from marshmallow_union import Union as UnionField  from validators.common import Gender   class CommaList(fields.Field):     def __init__(         self,         *,         load_default: typing.Any = missing_,         missing: typing.Any = missing_,         dump_default: typing.Any = missing_,         default: typing.Any = missing_,         data_key: str | None = None,         attribute: str | None = None,         validate: (             None             | typing.Callable[[typing.Any], typing.Any]             | typing.Iterable[typing.Callable[[typing.Any], typing.Any]]         ) = None,         required: bool = False,         allow_none: bool | None = None,         load_only: bool = False,         dump_only: bool = False,         error_messages: dict[str, str] | None = None,         metadata: typing.Mapping[str, typing.Any] | None = None,         **additional_metadata,     ) -> None:         super().__init__(             load_default=load_default,             missing=missing,             dump_default=dump_default,             default=default,             data_key=data_key,             attribute=attribute,             validate=validate,             required=required,             allow_none=allow_none,             load_only=load_only,             dump_only=dump_only,             error_messages=error_messages,             metadata=metadata,             **additional_metadata,         )         marshmallow_type = metadata.get('marshmallow_type') if metadata else None         self.marshmallow_type = marshmallow_type or (lambda x: x)      def _deserialize(self, value, attr, data, **kwargs) -> list:         try:             return [self.marshmallow_type(x) for x in value.split(',')]         except (ValueError, AttributeError, TypeError) as exc:             raise ValidationError('Incorrect list') from exc   class DocumentSchema(Schema):     class Meta:         unknown = EXCLUDE      number = UnionField(         data_key='full_number',         fields=[fields.Integer(), fields.Str()],         required=True,     )   class MarshmallowSchema(Schema):     class Meta:         unknown = EXCLUDE      schema_version = fields.Str(required=True, validate=validate.Equal('3.14.15'))     id = fields.UUID(required=True)     created_at = fields.DateTime(required=True)     name = fields.Str(required=True, validate=validate.Length(min=2, max=32))     age = fields.Int(required=True, validate=validate.Range(min=0, max=100))     is_client = fields.Bool(required=True)     gender = fields.Enum(Gender, by_value=True, required=True)     email = fields.Email(required=True)     social_profile_url = fields.URL(required=True)     bank_cards = fields.List(         fields.Str(validate=validate.Length(min=15)),         required=True,         validate=validate.Length(min=1),     )     countries = CommaList(required=True, metadata={'marshmallow_type': str})     document = fields.Nested(DocumentSchema)     page_number = fields.Int(required=True, validate=validate.Range(min=0, max=100))     page_size = fields.Int(required=True, validate=validate.Range(min=1, max=100))      @validates('created_at')     def date_must_be_in_past(self, value: datetime) -> None:         if value >= datetime.utcnow():             raise ValidationError('date must be in the past')      @validates('age')     def check_adults(self, value: int) -> None:         if value &lt; 18:             raise ValidationError('only adults')      @validates_schema     def general_check(self, data: dict, **kwargs) -> None:         if data.get('is_client') and not data.get('bank_cards'):             raise ValidationError('cards are required for clients')<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u043d\u0430\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044f: &#171;\u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u043d\u0438\u0435&#187; \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u0438\u043f\u043e\u0432, \u2013 \u0438\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0432\u0435\u0441\u044c\u043c\u0430 \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d\u043e. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c <code>CommaList<\/code> \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<h3>Trafaret<\/h3>\n<p>\u041e\u0447\u0435\u043d\u044c \u0440\u0435\u0434\u043a\u0438\u0439 \u0437\u0432\u0435\u0440\u044c \u0441 \u0441\u0430\u043c\u044b\u043c \u044d\u043a\u0437\u043e\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0441\u0445\u0435\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import uuid from datetime import datetime  import trafaret as t  from validators.common import Gender   class UUID(t.Trafaret):     def check_and_return(self, value: uuid.UUID | bytes | str | None) -> uuid.UUID | None:         if value is None:             return None         if isinstance(value, uuid.UUID):             return value         try:             if isinstance(value, bytes) and len(value) == 16:                 return uuid.UUID(bytes=value)             else:                 return uuid.UUID(value)         except (ValueError, AttributeError, TypeError):             self._failure('value is not a uuid')   class CommaList(t.Trafaret):     def __init__(self, *args, trafaret_type: t.Trafaret, **kwargs) -> None:         super().__init__(*args, **kwargs)         self.trafaret_type = trafaret_type      def check_and_return(self, data: str) -> list:         return [self.trafaret_type.check_and_return(x) for x in data.split(',')]   def past_date(frmt: str = '%Y-%m-%dT%H:%M:%S') -> t.And:     def check(value: str) -> datetime:         converted_value = datetime.fromisoformat(value)         if converted_value >= datetime.utcnow():             raise t.DataError('date must be in the past')         return converted_value      return t.DateTime(format=frmt) >> check   def check_adults(value: int) -> int:     if value &lt; 18:         raise t.DataError('only adults')     return value   def check_schema(data: dict) -> dict:     if data.get('is_client') and not data.get('bank_cards'):         raise t.DataError('cards are required for clients')     return data   document_schema = t.Dict(     {         t.Key('full_number') >> 'number': t.Int() | t.String(),     }, )  trafaret_schema = (     t.Dict(         {             'schema_version': t.Atom('3.14.15'),             'id': UUID,             'created_at': past_date(),             'name': t.String(min_length=2, max_length=32),             'age': t.Int(gte=0, lte=100) >> check_adults,             'is_client': t.Bool(),             'gender': t.Enum(*[i.value for i in Gender]),             'email': t.Email,             'social_profile_url': t.URL,             'bank_cards': t.List(t.Int(gte=10**15), min_length=1),             'countries': CommaList(trafaret_type=t.String()),             'document': document_schema,             'page_number': t.Int(gte=0, lte=100),             'page_size': t.Int(gte=1, lte=100),         },         ignore_extra='*',     )     >> check_schema )<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043d\u043e\u0432\u044c \u0432\u0435\u0440\u043d\u0443\u043b\u0438\u0441\u044c \u043a \u0442\u0438\u043f\u0430\u043c, \u043f\u0443\u0441\u0442\u044c \u0438 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c. \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0430\u0441\u043a\u0435\u0442\u0438\u0447\u043d\u043e, \u043d\u043e \u0442\u0438\u043f\u043e\u0432 &#171;\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438&#187; \u0432 \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435, \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u043c\u0435\u043d\u044c\u0448\u0435 \u0432\u0441\u0435\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0434\u0432\u0443\u0445 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 Trafaret \u043c\u043e\u0436\u0435\u0442 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0442\u043f\u0443\u0433\u043d\u0443\u0442\u044c, \u043d\u043e \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0448\u044c, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u043c \u0447\u0442\u043e-\u0442\u043e \u0435\u0441\u0442\u044c.<\/p>\n<h3>Django REST framework (DRF)<\/h3>\n<p>\u0421\u043b\u043e\u0436\u043d\u043e \u043e\u0442\u0434\u0435\u043b\u0438\u0442\u044c DRF \u043e\u0442 Django, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 Pydantic \u0438 FastApi. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a \u0432\u0437\u044f\u0442\u044c \u0438 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u043d\u0443\u0436\u043d\u043e \u0431\u043e\u0440\u043e\u0442\u044c\u0441\u044f \u0441 \u0432\u043e\u043b\u043e\u0447\u0430\u0449\u0438\u043c\u0441\u044f Django: \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u043b\u0430\u0442\u044c monkeypatch \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a (django.settings). \u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0440\u0435\u0437\u0435 \u0441\u0430\u043c\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0438\u0437 \u043e\u0431\u043e\u0437\u0440\u0435\u0432\u0430\u0435\u043c\u044b\u0445.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0441\u0445\u0435\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from datetime import datetime  from rest_framework import serializers as s  from validators.common import Gender   def check_schema_version(value: str) -> None:     if value != '3.14.15':         raise s.ValidationError('value must be equal \"3.14.15\"')   class CommaStrListField(s.Field):     def to_representation(self, value: list[str]) -> list[str]:         return value      def to_internal_value(self, data: str) -> list[str]:         try:             return [str(x) for x in data.split(',')]         except (ValueError, AttributeError, TypeError) as exc:             raise s.ValidationError('Incorrect list') from exc   class IntOrStrField(s.Field):     def to_representation(self, value: int | str) -> int | str:         return value      def to_internal_value(self, data: int | str) -> int | str:         return data   class DocumentSchema(s.Serializer):     full_number = IntOrStrField(source='number')   class DRFSchema(s.Serializer):     class Meta:         unknown = 'ignore'      schema_version = s.CharField(validators=[check_schema_version])     id = s.UUIDField()     created_at = s.DateTimeField()     name = s.CharField(min_length=2, max_length=32)     age = s.IntegerField(min_value=0, max_value=100)     is_client = s.BooleanField()     gender = s.ChoiceField(choices=[(e.value, e.name) for e in Gender])     email = s.EmailField()     social_profile_url = s.URLField()     bank_cards = s.ListField(child=s.CharField(min_length=15))     countries = CommaStrListField()     document = DocumentSchema()     page_number = s.IntegerField(min_value=0, max_value=100)     page_size = s.IntegerField(min_value=1, max_value=100)      def validate_created_at(self, value: datetime) -> datetime:         if value >= datetime.utcnow():             raise s.ValidationError('date must be in the past')         return value      def validate_age(self, value: int) -> int:         if value &lt; 18:             raise s.ValidationError('only adults')         return value      def validate(self, data: dict) -> dict:         if data.get('is_client') and not data.get('bank_cards'):             raise s.ValidationError('cards are required for clients')         return data<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0432\u043d\u043e\u0432\u044c \u0443\u0448\u043b\u0438 \u043e\u0442 \u0442\u0438\u043f\u043e\u0432. \u041d\u0435 \u0438\u0437\u0431\u0435\u0436\u0430\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0431\u044b\u0442\u044c &#171;\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438&#187;.<\/p>\n<p>DRF \u043f\u0440\u0438\u043d\u0443\u0436\u0434\u0430\u0435\u0442 \u043d\u0430\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u00ab\u0435\u0434\u0438\u043d\u044b\u0439\u00bb \u0441\u0442\u0438\u043b\u044c \u0434\u043b\u044f \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u043e\u0432. \u041d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d, \u0447\u0442\u043e \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e \u043e\u0442\u043d\u0435\u0441\u0442\u0438 \u043a \u043f\u043b\u044e\u0441\u0430\u043c \u0438\u043b\u0438 \u043c\u0438\u043d\u0443\u0441\u0430\u043c.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u0442\u0440\u0430\u043d\u043d\u043e, \u0447\u0442\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432\u0438\u0434\u0430 <code>Union<\/code> \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0442\u0438\u043f. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0442\u0443\u0442 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0434\u0435\u043b\u0430\u044e, \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u0441\u043f\u043e\u0440\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435.<\/p>\n<h2> \u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/h2>\n<p>\u0423 \u043a\u0430\u0436\u0434\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0432 \u0437\u0430\u043a\u0440\u043e\u043c\u0430\u0445 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0439 \u0442\u0435\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u043b\u0438\u0431\u0430 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043a\u0440\u0443\u0442\u0430\u044f, \u044f \u0436\u0435 \u043d\u0430\u043f\u0438\u0448\u0443 \u0441\u0432\u043e\u0439. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0441\u044c\u043c\u0430 \u043d\u0435\u0442\u043e\u0447\u043d\u044b\u0439, \u043d\u043e \u043f\u0440\u0438\u043a\u0438\u043d\u0443\u0442\u044c \u043f\u0430\u043b\u0435\u0446 \u043a \u043d\u043e\u0441\u0443 \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0436\u043d\u043e.<\/p>\n<details class=\"spoiler\">\n<summary>\u0424\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from enum import StrEnum, unique  import pytest from faker import Faker   @pytest.fixture(scope='session') def faker() -> Faker:     return Faker('en_GB')   @unique class Gender(StrEnum):     MALE = 'male'     FEMALE = 'female'     HELICOPTER = 'helicopter'   @pytest.fixture def data(faker: Faker) -> dict:     return {         'schema_version': '3.14.15',         'id': faker.uuid4(cast_to=None),         'created_at': faker.past_datetime().isoformat().split('.')[0],         'name': faker.name(),         'age': faker.pyint(min_value=18, max_value=100),         'is_client': faker.pybool(),         'gender': faker.enum(Gender).value,         'email': faker.email(),         'social_profile_url': faker.url(),         'bank_cards': (             [                 faker.credit_card_number('visa16')                 for _ in range(faker.pyint(min_value=1, max_value=3))             ]             if faker.pybool             else None         ),         'countries': ','.join(             [faker.currency_code() for _ in range(faker.pyint(min_value=1, max_value=5))]         ),         'document': {             'full_number': faker.pyint() if faker.pybool() else faker.pystr(),         },         'page_number': faker.pyint(min_value=0, max_value=10),         'page_size': faker.pyint(min_value=1, max_value=100),     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0434\u0430\u043b\u0435\u0435 \u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435. \u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u0434\u043b\u044f Pydantic:<\/p>\n<pre><code class=\"python\">def test_pydantic(data: dict) -> None:     count = 10**5     execution_time = timeit.timeit(stmt=lambda: PydanticSchema(**data), number=count)     print('pydantic', count, execution_time)<\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u0430\u043a\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b:<\/p>\n<ol>\n<li>\n<p>Pydantic (6.85 \u0441\u0435\u043a)<\/p>\n<\/li>\n<li>\n<p>Trafaret (7.23 \u0441\u0435\u043a)<\/p>\n<\/li>\n<li>\n<p>Marshmallow (26.43 \u0441\u0435\u043a)<\/p>\n<\/li>\n<li>\n<p>DRF (36.42 \u0441\u0435\u043a)<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e, \u043d\u043e Trafaret \u043e\u0431\u0433\u043e\u043d\u044f\u0435\u0442 Marshmallow \u043d\u0430 \u0434\u0432\u0430 \u043a\u043e\u0440\u043f\u0443\u0441\u0430 \u0438 \u0434\u044b\u0448\u0438\u0442 \u043b\u0438\u0434\u0435\u0440\u0443 \u0432 \u0437\u0430\u0442\u044b\u043b\u043e\u043a. \u041f\u0435\u0440\u0432\u043e\u0435 \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043c\u0435\u0441\u0442\u043e \u043d\u0435 \u043f\u0440\u0438\u043d\u0435\u0441\u043b\u0438 \u0441\u044e\u0440\u043f\u0440\u0438\u0437\u043e\u0432.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043e \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u043c \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0442\u043e, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0438\u043c \u0436\u0435.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043a\u043e\u0434 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0438\u0441\u0430\u043b\u0441\u044f \u0432 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 22 \u0433\u043e\u0434\u0430. \u0427\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043a \u044d\u0442\u043e\u0439 \u0438\u0434\u0435\u0435 \u044f \u0432\u0435\u0440\u043d\u0443\u043b\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0433\u043e\u0434 \u2013 \u0432 \u0434\u0435\u043a\u0430\u0431\u0440\u0435 23. \u0421\u0435\u0439\u0447\u0430\u0441 \u0443\u0436\u0435 \u0432\u0435\u0441\u043d\u0430 24, \u0438 \u044f \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u043a\u0440\u0430\u0441\u0442\u0438\u043d\u0430\u0446\u0438\u044f \u0432\u0441\u0451 \u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0431\u0435\u0436\u0434\u0435\u043d\u0430 (\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043e\u043f\u0438\u0441\u0430\u043d\u0430), \u043d\u043e \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043a\u0430\u043a \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u043e\u0431\u043e\u0437\u0440\u0435\u0432\u0430\u0435\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0437\u0430 \u0433\u043e\u0434 \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c.<\/p>\n<details class=\"spoiler\">\n<summary>\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">pydantic[email]==2.6.4 pydantic-extra-types==2.6.0 pycountry==23.12.11 marshmallow==3.21.1 marshmallow-union==0.1.15.post1 trafaret==2.1.1 djangorestframework==3.14.0<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u0430 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0432 Marshmallow \u0437\u0430\u0432\u0435\u0437\u043b\u0438 <code>Enum<\/code> (\u0430 <code>Union<\/code> \u0432\u0441\u0435 \u0435\u0449\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e), \u0430 Pydantic \u043e\u0431\u043d\u043e\u0432\u0438\u043b \u043c\u0430\u0436\u043e\u0440\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e (\u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0435\u0439 \u0438 \u0440\u0435\u043a\u043e\u0440\u0434\u044b \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438). \u0410 \u0432\u043e\u0442 \u0443 Trafaret \u0437\u0430 \u044d\u0442\u043e\u0442 \u043f\u0435\u0440\u0438\u043e\u0434 \u0432\u044b\u0448\u043b\u043e \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435; \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u043e\u043d\u0438 \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0438 \u0434\u0437\u0435\u043d\u0430.<\/p>\n<p>\u041c\u043d\u043e\u0433\u0438\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0444\u0438\u0448\u043a\u0438 \u043d\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u043d\u043e \u043e \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438. \u0422\u0430\u043a\u0438\u0435 \u043a\u0430\u043a:<\/p>\n<ul>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 json \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, orjson), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u0435\u0449\u0430\u044e\u0442 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u0443\u044e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 (frozen)<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435\/merge \u0441\u0445\u0435\u043c<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0435\u0449\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0434\u0440\u0443\u0433\u0438\u0445: Cerberus, jsonschema, WTForms, \u2013 \u043d\u043e, \u043f\u043e\u043b\u0430\u0433\u0430\u044e, \u043e\u043d\u0438 \u0443\u0436\u0435 \u0432 \u0441\u0442\u0430\u0442\u0443\u0441\u0435 \u043b\u0435\u0433\u0430\u0441\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043d\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043d\u0435 \u043f\u043e\u043f\u0430\u0434\u0443\u0442.<\/p>\n<p>P.S. \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0447\u0442\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0438\u043b\u0438 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f\u0445, \u0441\u043c\u0435\u043b\u043e \u043f\u0438\u0448\u0438\u0442\u0435 \ud83d\ude42<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/800837\/\"> https:\/\/habr.com\/ru\/articles\/800837\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 (\u0442\u0435\u043f\u0435\u0440\u044c \u0443\u0436 \u0441 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u043e\u0439):<\/p>\n<pre><code class=\"python\">def handler_create_user(r: Request):     input_data = r.post()     first_name, email = input_data.get('firstName'), input_data.get('email')     if not first_name or not email:         raise HTTPBadRequest('name &amp; email must have values')     return User.create(name=first_name, email=email, password=uuid4())<\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u043a\u0430\u043a\u0438\u0435 \u0442\u0443\u0442 \u0435\u0441\u0442\u044c \u0443\u0437\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430?<\/p>\n<ul>\n<li>\n<p>\u041c\u044b \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u043d\u0435 \u0438\u043c\u0435\u0435\u043c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043a\u0430\u043a\u0438\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u043a\u043b\u044e\u0447\u0438), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043e\u0441\u0442\u0430\u0435\u043c, \u043d\u0430\u0434\u0435\u044f\u0441\u044c \u043d\u0430 \u0443\u0441\u043f\u0435\u0445, \u0447\u0435\u0440\u0435\u0437 <code>get<\/code>, \u0430 \u043f\u043e\u0442\u043e\u043c \u0432\u044b\u043d\u0443\u0436\u0434\u0435\u043d\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0447\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0451 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u043e\u0435<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044f \u0441\u0442\u0438\u043b\u0435\u0439 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 (Snake case, Camel case, etc.) \u0442\u043e\u0436\u0435 \u043b\u043e\u0436\u0438\u0442\u0441\u044f \u043d\u0430 \u0445\u0440\u0443\u043f\u043a\u0438\u0435 \u043f\u043b\u0435\u0447\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437 \u0442\u0435\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0442.\u043e. \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u0432\u0438\u0434\u0430 <code>my_var = input_data.get('my_var')<\/code> \u043c\u043e\u0433\u0443\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u201c\u0437\u0430\u0433\u0440\u044f\u0437\u043d\u0438\u0442\u044c\u201d \u043a\u043e\u0434<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0442\u0443\u0442 \u0436\u0435 (\u0432 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0435), \u0438 \u043e\u043d\u0430 \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u043e\u0439<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u044f\u0432\u043d\u043e \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u0432 (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2013 \u043e\u0442 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445). \u0422.\u043e. \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0432 \u043c\u043e\u0434\u0435\u043b\u044c, \u043e\u043d\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u0438 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0441\u043b\u043e\u043c\u0430\u0442\u044c API<\/p>\n<\/li>\n<li>\n<p>\u0412 response \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u043d\u0435\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0430\u0440\u043e\u043b\u044c \u0438\u043b\u0438 \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447)<\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u043e\u0436\u043d\u043e \u043b\u0438 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u0443\u0436\u0435? \u041a\u043e\u043d\u0435\u0447\u043d\u043e!<\/p>\n<pre><code class=\"python\">def handler_create_user(r: Request):     return User.create(**r.post(), password=uuid4())<\/code><\/pre>\n<p>\u0410 \u0432\u043e\u0442 \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043b\u0443\u0447\u0448\u0435, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h2>\u041a\u0430\u043a \u044d\u0442\u043e \u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c<\/h2>\n<p>\u0421\u0440\u0430\u0437\u0443 \u043e\u0433\u043e\u0432\u043e\u0440\u044e\u0441\u044c, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0430\u0437\u0440\u0435\u0437\u0435 \u0440\u0430\u0431\u043e\u0442\u044b API \u0431\u0435\u043a\u0435\u043d\u0434\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0434\u043b\u044f desktop \u0441\u0438\u0441\u0442\u0435\u043c \u043f\u043e\u0434\u0445\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0438\u043d\u044b\u043c.<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u0442\u044c \u0441\u043b\u0443\u0447\u0430\u0438, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043d\u0435 \u043d\u0443\u0436\u043d\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b \u0441\u0442\u0430\u0440\u0442\u0430\u043f, \u0441\u0440\u043e\u043a \u0436\u0438\u0437\u043d\u0438 \u043a\u043e\u0434\u0430 \u2013 \u043e\u0434\u043d\u0430 \u043d\u0435\u0434\u0435\u043b\u044f, \u043d\u0435\u043a\u043e\u0433\u0434\u0430 \u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u0430\u0434\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u043e<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u2013 \u044d\u0442\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0442\u043e\u0438\u0442 \u043b\u0438\u0448\u044c \u043d\u0430 \u0441\u0442\u044b\u043a\u0435 \u0441\u0438\u0441\u0442\u0435\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0438\u0448\u043b\u043e \u0438\u0437\u0432\u043d\u0435, \u0430 \u0434\u0430\u043b\u0435\u0435, \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043c\u044b \u0441\u0430\u043c\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435. \u041c\u043e\u0436\u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u0434\u0443\u043c\u0430\u0442\u044c \u043a\u0430\u043a \u043e \u043d\u0435\u043a\u043e\u0439 \u0433\u0440\u0430\u043d\u0438\u0446\u0435, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442, \u0430 \u0434\u0430\u043b\u0435\u0435 \u043d\u0438\u043a\u0442\u043e \u043f\u0430\u0441\u043f\u043e\u0440\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 (\u0434\u0430 \u0438 \u043d\u0435 \u043d\u0430\u0434\u043e, \u0432\u0435\u0434\u044c \u0432\u0441\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0436\u0435 \u043f\u043e\u0434 \u043d\u0430\u0448\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u043c)<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u0447\u0435\u043c, \u044d\u0442\u0443 \u0433\u0440\u0430\u043d\u0438\u0446\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u044f\u0442 \u043a\u0430\u043a \u043f\u043e \u201c\u043f\u0440\u0438\u0435\u0437\u0434\u0435\u201d, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438 \u201c\u043e\u0442\u044a\u0435\u0437\u0434\u0435\u201d. \u0412\u0430\u0436\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0445\u043e\u0434, \u043d\u043e \u0438 \u0432\u044b\u0445\u043e\u0434, \u0438\u0431\u043e \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043d\u0435 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 ORM \u043c\u043e\u0434\u0435\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0440\u0443\u0436\u0443, \u0434\u0430 \u0438 \u0441\u0430\u043c\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c, \u0442.\u043a. \u043e\u0442\u0432\u0435\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044d\u0442\u043e \u0434\u0430\u0441\u0442 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u0430\u0448\u0435\u0433\u043e API: \u0447\u0451\u0442\u043a\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043e\u0442\u0432\u0435\u0442\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c\u0441\u044f<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u0442\u044c \u0441 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0435\u0439 (\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c, cast) \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043c\u044b \u0436\u0434\u0451\u043c \u0432 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435 \u0434\u0430\u0442\u0443, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u044f\u0442\u043d\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0447\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0430\u0442\u0430, \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0435\u0449\u0435 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044f <code>str -> datetime<\/code>; \u0438\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u0441\u044f \u0432 <code>enum<\/code><\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0443\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u0441\u0430\u0439\u0442 \u0438\u043b\u0438 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043d\u0430 \u0434\u0432\u0443\u0445 \u0443\u0440\u043e\u0432\u043d\u044f\u0445: \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0444\u0440\u043e\u043d\u0442\u0430 (\u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u0434\u0443\u0440\u0430\u043a\u0430) \u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0431\u0435\u043a\u0430 (\u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u0445\u0430\u043a\u0435\u0440\u0430). \u041f\u043e\u0440\u043e\u0439 \u043f\u0435\u0440\u0432\u044b\u043c \u043f\u0440\u0435\u043d\u0435\u0431\u0440\u0435\u0433\u0430\u044e\u0442 \u0432 \u0443\u0433\u043e\u0434\u0443 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043f\u043e\u043b\u0443\u0447\u0430\u044f \u0431\u043e\u043d\u0443\u0441\u043e\u043c \u0443\u0445\u0443\u0434\u0448\u0435\u043d\u0438\u0435 UX \u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0435 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0441\u0435\u0442\u044c; <span class=\"habrahidden\">\u043f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440<\/span>), \u043d\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u2013 \u044d\u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0440\u0443\u0431\u0435\u0436 \u043e\u0431\u043e\u0440\u043e\u043d\u044b, \u0438\u043d\u0430\u0447\u0435 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0432\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u0436\u0434\u0430\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0431\u0430\u0437\u0435, \u0430 \u0432\u044b \u0438\u0445 \u0442\u043e\u0447\u043d\u043e \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u0434\u0435\u043b\u0430\u0442\u044c<\/p>\n<\/li>\n<li>\n<p>\u0412 MVC-like \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 (view) \u0431\u0443\u0434\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0441\u0442\u044b\u043c, \u0442.\u043a. \u0432\u0441\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0432 \u0441\u0445\u0435\u043c\u0430\u0445. \u0414\u0430 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c \u0443\u0434\u043e\u0431\u043d\u0435\u0435<\/p>\n<\/li>\n<\/ul>\n<h2> Show me the code<\/h2>\n<p>\u0421\u0440\u0430\u0432\u043d\u0438\u043c \u0447\u0435\u0442\u044b\u0440\u0435 Python \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u0438\u043d\u0442\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0442\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u0435\u043b\u044f json\u2019\u043e\u0432 (a.k.a. backend developer) \u0430 \u0442\u0430\u043a \u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a. \u0411\u043e\u043d\u0443\u0441\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043d\u0435\u043a\u0443\u044e \u0448\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u0430 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0441\u0432\u0435\u0436\u0438\u0442\u044c \u043f\u0430\u043c\u044f\u0442\u044c \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0411\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430 \u0432\u0445\u043e\u0434 \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0442.\u0435. \u043d\u0435 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (request) \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u044d\u0442\u043e\u0442 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0438 \u043a\u0430\u043a \u043f\u043e\u0442\u043e\u043c \u0438\u0437 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0441\u043e\u0437\u0434\u0430\u0441\u0442\u0441\u044f json \u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430 (response).<\/p>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0435\u0449\u0451 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0434\u043d\u043e \u0438\u0437 \u043f\u043e\u043b\u0435\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u043e\u043c \u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0435\u0449\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c sql \u0437\u0430\u043f\u0440\u043e\u0441. \u042d\u0442\u043e \u043f\u043e\u0445\u0432\u0430\u043b\u044c\u043d\u043e, \u043d\u043e \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 (dependency) \u0432 \u0441\u0445\u0435\u043c\u044b \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043e\u0442\u043a\u0440\u043e\u0435\u0442 \u043f\u043e\u0440\u0442\u0430\u043b \u0432 \u0430\u0434, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0437\u0434\u043d\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u0432 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043e\u0442\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445.<\/p>\n<h3>Pydantic<\/h3>\n<p>\u0414\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f, \u0442.\u043a. \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0445\u0430\u0439\u043f\u044f\u0449\u0435\u0433\u043e FastApi.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0441\u0445\u0435\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from typing import Annotated, ClassVar, Literal  from pydantic import (     UUID4,     BaseModel,     ConfigDict,     EmailStr,     Field,     HttpUrl,     NonNegativeInt,     PastDatetime,     PositiveInt,     field_validator,     model_validator, ) from pydantic_extra_types.country import CountryAlpha3 from pydantic_extra_types.payment import PaymentCardNumber  from validators.common import Gender   class DocumentSchema(BaseModel):     number: Annotated[int | str, Field(alias='full_number')]   class PydanticSchema(BaseModel):     model_config: ClassVar = ConfigDict(extra='ignore')          schema_version: Literal['3.14.15']     id: UUID4     created_at: PastDatetime     name: Annotated[str, Field(min_length=2, max_length=32)]     age: Annotated[int, Field(ge=0, le=100)]     is_client: bool     gender: Gender     email: EmailStr     social_profile_url: HttpUrl     bank_cards: list[PaymentCardNumber] | None     countries: Annotated[str, Field(min_length=1, max_length=64)]     document: DocumentSchema     page_number: NonNegativeInt     page_size: PositiveInt      @field_validator('age', mode='after')     @classmethod     def check_adults(cls, value: int) -> int:         if value &lt; 18:             raise ValueError('only adults')         return value      @field_validator('countries')     @classmethod     def parse_counties(cls, value: str) -> list[CountryAlpha3]:         return [CountryAlpha3(c) for c in value.split(',')]      @model_validator(mode='before')     @classmethod     def general_check(cls, data: dict) -> dict:         if data.get('is_client') and not data.get('bank_cards'):             raise ValueError('cards are required for clients')         return data<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0443\u0442 \u0432 \u0445\u0432\u043e\u0441\u0442 \u0438 \u0433\u0440\u0438\u0432\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0442\u0438\u043f\u043e\u0432, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u043e\u0434 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u043c \u0438 \u043f\u0440\u0438\u044f\u0442\u043d\u044b\u043c. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0440\u0430\u043d\u044c\u0448\u0435 \u0431\u044b\u043b\u0438 \u0447\u0430\u0441\u0442\u044c\u044e Pydantic, \u043d\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443.<\/p>\n<h3>Marshmallow<\/h3>\n<p>\u0412 \u043c\u043e\u0435\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 aiohttp \u0438\u043b\u0438 Flask.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0441\u0445\u0435\u043c\u044b<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import typing from datetime import datetime  from marshmallow import (     EXCLUDE,     Schema,     ValidationError,     fields,     validate,     validates,     validates_schema, ) from marshmallow.utils import missing as missing_ from marshmallow_union import Union as UnionField  from validators.common import Gender   class CommaList(fields.Field):     def __init__(         self,         *,         load_default: typing.Any = missing_,         missing: typing.Any = missing_,         dump_default: typing.Any = missing_,         default: typing.Any = missing_,         data_key: str | None = None,         attribute: str | None = None,         validate: (             None             | typing.Callable[[typing.Any], typing.Any]             | typing.Iterable[typing.Callable[[typing.Any], typing.Any]]         ) = None,         required: bool = False,         allow_none: bool | None = None,         load_only: bool = False,         dump_only: bool = False,         error_messages: dict[str, str] | None = None,         metadata: typing.Mapping[str, typing.Any] | None = None,         **additional_metadata,     ) -> None:         super().__init__(             load_default=load_default,             missing=missing,             dump_default=dump_default,             default=default,             data_key=data_key,             attribute=attribute,             validate=validate,             required=required,             allow_none=allow_none,             load_only=load_only,             dump_only=dump_only,             error_messages=error_messages,             metadata=metadata,             **additional_metadata,         )         marshmallow_type = metadata.get('marshmallow_type') if metadata else None         self.marshmallow_type = marshmallow_type or (lambda x: x)      def _deserialize(self, value, attr, data, **kwargs) -> list:         try:             return [self.marshmallow_type(x) for x in value.split(',')]         except (ValueError, AttributeError, TypeError) as exc:             raise ValidationError('Incorrect list') from exc   class DocumentSchema(Schema):     class Meta:         unknown = EXCLUDE      number = UnionField(         data_key='full_number',         fields=[fields.Integer(), fields.Str()],         required=True,     )   class MarshmallowSchema(Schema):     class Meta:         unknown = EXCLUDE      schema_version = fields.Str(required=True, validate=validate.Equal('3.14.15'))     id = fields.UUID(required=True)     created_at = fields.DateTime(required=True)     name = fields.Str(required=True, validate=validate.Length(min=2, max=32))     age = fields.Int(required=True, validate=validate.Range(min=0, max=100))     is_client = fields.Bool(required=True)     gender = fields.Enum(Gender, by_value=True, required=True)     email = fields.Email(required=True)     social_profile_url = fields.URL(required=True)     bank_cards = fields.List(         fields.Str(validate=validate.Length(min=15)),         required=True,         validate=validate.Length(min=1),     )     countries = CommaList(required=True, metadata={'marshmallow_type': str})     document = fields.Nested(DocumentSchema)     page_number = fields.Int(required=True, validate=validate.Range(min=0, max=100))     page_size = fields.Int(required=True, validate=validate.Range(min=1, max=100))      @validates('created_at')     def date_must_be_in_past(self, value: datetime) -> None:         if value >= datetime.utcnow():             raise ValidationError('date must be in the past')<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-371026","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/371026","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=371026"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/371026\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=371026"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=371026"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=371026"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}