Приложение на Django + DRF и сравнение с FastAPI-JSON:API

Приложение на Django + DRF и сравнение с FastAPI-JSON:API03:14:26

Информация о загрузке и деталях видео Приложение на Django + DRF и сравнение с FastAPI-JSON:API

Автор:

Сурен Хоренян

Дата публикации:

13.04.2025

Просмотров:

2K

Транскрибация видео

Так, меня должно быть видно-слышно.

Вопрос только, на каких площадках уже началась трансляция, на каких нет.

Смотрю.

что в вк эфир идет сейчас проверю что я там уже в кадре пока что нет задержка видимо сейчас рутуб проверим ютубчик запустил уже только я не вижу как мне комменты открыть очень странно сделано на опа звук есть

Да, ВК все окей.

Значит, платформа все окей.

Рутуб.

Надеюсь, что все окей.

И я тогда могу анонсировать в Телеге, что мы стартуем.

И мы стартанем.

Так, live chat.

Я, допустим, хочу сделать это pop-up chat.

Как это делается?

Раньше была кнопка, вот pop-out.

Я хочу вот эту ссылку открыть у себя на планшете, чтобы видеть, что происходит.

Откроется ли эта ссылка?

Откроется ли?

Вот в чем вопрос.

Блин, раньше на iPad был Snap к сторонам, а теперь это отдельные окна, что выглядит супер неудобно.

Это, наверное, потому что у меня Stage Manager.

Сейчас я это еще сделаю.

Да, вот Snap есть.

Окей.

Так, вижу, что, получается, у меня Live Chat теперь выведен.

На iPad я смогу смотреть ваши комменты сразу, как вы их пишете.

Если оно, конечно, тут будет работать, а то у меня есть сомнения на этот счет.

Сейчас посмотрим.

И слушайте, 30 минут, а мы уже в эфире.

И у нас уже все схвачено.

Мы сейчас только в тележку кинем анонс, что мы стартанули, а то там ждут люди.

И все.

Сейчас я трансляцию на Рутубе тоже открою здесь, чтобы я видел комменты.

Да, вот чат.

Слышим, видим хорошо.

Прекрасно.

Прекрасно.

Все, тогда я могу сделать...

Сделать так.

Все.

Чат на Рутубе удобнее смотреть, чем на Ютубе.

Ну, если на Ютубе вы меня видите, слышите, тоже дайте знать.

Окей.

Все, тогда мы стартуем.

Сегодня мы поговорим... Да, сейчас я в телеку закину.

Сегодня мы поговорим про работу с Django и Django REST Framework.

Я хочу сравнить, что мы с вами...

делали на предыдущих эфирах на фастапе с библиотечкой JSON API, JSON 2000 API, которую я пилил, ну, не один.

И посмотрим, получится ли нам за один эфир сделать то, что мы там делали два с половиной эфира.

Если мы сильно быстро закончим, в чем я сомневаюсь, то мы еще зайдем там в мерч и квест, еще пару комментов оставили, которые мы уже сколько пилим.

Поэтому...

Там нам будет что делать.

Короче, мы часа на 2-3 здесь, я думаю, прям крепко засели.

Так, кидаю анонс в тележку.

Ссылку на видео, как скопировать, поделиться.

Вставляю ссылку на ВК.

Так, ссылку на Рутуб.

Поделиться.

Ссылка скопирована.

На телегу.

В телегу уже идет.

И на платформу.

Тут каждый раз неудобно шерить.

Тут надо идти на мой канал.

Там в трансляции.

И вот отсюда скопировать.

Я знаю, что вы не видите, но хотя бы не молчу.

И вот для платформы вставляем ссылочку.

Все.

Мы уже в эфире.

Класс.

Так, привет.

Да, вижу, коммент на ютубе есть, но он... Во, все, наконец-то.

Не скроллилось.

Видно и слышно.

Прекрасно.

Все, тогда начинаем.

Все, всех позвал.

Значит, это я закрою.

И я открою БС, чтобы вам... Чтобы видеть, что я вам показываю.

Все.

Если будут какие-то проблемы по звуку, по видео, вы обязательно пишите сразу в чат.

Я мониторю.

Я буду... Короче, наблюдать, что происходит.

Угу.

интересно как это сделать

New Window, где вот тут?

Нет в Safari New Window.

Ну ладно, так справимся.

Привет.

Да, всем привет.

Окей.

Тогда мы пишем Django.

А, да, Donation Alerts не включил.

Django.

Сейчас будем вставить Django.

И я включу только еще момент Donation Alerts.

Для этого мне нужно... Что мне нужно?

Мне нужно...

Я забыл, как я это делал.

Добавить сцену.

Добавить сцену.

Добавить сцену.

Сцена.

Вот.

И у меня тут есть сцена Donation Alerts.

Вот.

Все.

Должны загрузиться сейчас виджеты.

Все, виджеты есть.

И, кстати, последний донат вот тут написано.

Короче, это было в феврале еще.

И мне, оказывается, там заморозили вывод.

Я только заметил сейчас, ну вот пару дней назад писал в чатике.

Написал им в поддержку.

Но я не знал, что заморозили.

Я просто вижу, что деньги до сих пор не выведены.

Я пишу им, а они такие, ну, как бы, подтвердите, что вы стримите.

Я такой, ну вот, пожалуйста, эфиры.

Такие, ладно, разморозили, но это впредь не нарушайте, хотя я и так не нарушал.

Ну, типа, если что, через нас продавать нельзя.

Это только для нанатов.

Я такой, ну, как бы, я только для нанатов.

Можно было бы погромче.

А, о, спасибо.

Это я не проверил.

Гейн был минус 10.

Ставлю минус 2.

Гейн минус 2 сейчас.

Должно быть, меня сильно громче слышно, но из-за этого будут перегрузки.

Я попробую что-то с этим делать, если вы мне будете подсказывать, что, ну, в целом, слышно, не слышно.

Вот, я тут поставил сейчас гейн минус 2.

Ну, вижу, пока в красный не уходит, но вот, хотя, видите, появляется надо красный.

То есть где-то, вот, он перегружается, звук.

Вот, может быть, мне надо еще сильнее...

Так, это релиз, рейшот, рейшхолд, может надо поправить.

Короче, если будет сильно плохо, вы мне скажите.

Вот, а пока, пока так.

Вот, если стало лучше, то... Приветствую, запись будет?

Да, запись будет, конечно же.

Хорошо, стрима, спасибо большое.

Так, и да, что мы будем делать?

У нас есть наше приложение Example, как там, FastAppy, JSONAppy.

Как же я там называл?

Так, давайте просто знаете как сделаем?

Зайдем на канал.

Ой, в хроме глюк какой-то.

Короче, смотрите, набираю Сурен.

Он мне... Сейчас.

Набираю собачка Сурен.

Он мне предлагает ссылку.

Сейчас не предлагает, кстати.

Сурен.

Странно.

Смотрите, вообще не предлагает.

Так, если я пишу YouTube, нажимаю Tab...

Сейчас нормально.

Дальше слэш, собачка, сурен.

Смотрите, пропало полностью, хотя только что предлагал.

Было точно в запсе, думаю, можно будет проверить.

Так вот, на предыдущем эфире мы делали лайв.

Вот здесь, смотрите, первый эфир 3.2, потом 1.000, потом 800 вообще скатился.

Так вот, идем просто на... Код тут, вот.

Вот, в стапе JSONAPI example movies каталог.

Вот, мы сейчас что-нибудь подобное, не один в один, но подобное сделаем на Django.

Такой вопрос, что лучше для начала, Django или FastTap?

Я смотрю, для какого начала, что вы собираетесь делать.

Это все-таки разные инструменты, хоть и для решения более-менее похожих задач.

Если вы хотите разобраться, как вообще веб-фреймворки работают, то я бы начал с FastTap.

Но если вы готовы разбираться, а если вы хотите пилить приложение, то на Django надо.

Насколько актуален Django плюс DRF?

На GitHub звезд у FastApp чуть больше, чем у Django.

Звезды ничего не значат.

Ну, в смысле, ладно, они значат, но, скажем так, если их переваливать за несколько тысяч, то все хорошо.

И неважно, там уже 10 тысяч или 100 тысяч.

Сорян, привет, хорошего стрима и настроения, спасибо большое, будешь когда-нибудь снимать видео про язык программирования Go?

У меня есть кое-что в планах, это не то, что вы ожидаете, но это не то, что вы просили, а то, что вам нужно.

Короче, это будет не раньше осени, это будет касаться курса, который уже запущен.

Я в чатике скидывал ссылку на канале, уже анонсировал на предыдущем эфире.

В сторону хорошего стрима.

Спасибо большое.

Спасибо.

Вот.

Короче, но пока без спойлеров.

Ну, короче, что-то будет, но не в ближайшее время.

То есть в конце лета в лучшем случае.

Я сейчас потихоньку записываю.

Вот сегодня записывал штук 6 роликов, снял в рамках курса.

Вот потихоньку публикую.

Там раз в неделю выходит новый модуль.

Да, если что, ссылку можно посмотреть, если вы просто на эфир в описании зайдете, то вот здесь.

Ссылка на все мои ссылки.

Я пока прямо отдельно ссылку не пихаю.

Вот здесь вот программа на Stepik.

Переходим.

И, ну, тут открывается сразу же с применением промокода.

Потом заново можете перейти, чтобы промокод применился.

Блин, он мне показывает каждый раз, вот я ведусь на это.

Он мне почему-то, если я перехожу, когда я автор, то он мне открывает админку, вместо того, чтобы открыть программу.

То есть вот я хочу закрыть, и вот я попадаю на страницу.

Короче, вот здесь описано все, что будет.

И это вот почти все, что здесь выведено, вот здесь оно уже выложено.

Вот, но это еще в процессе выкладывания.

Короче, будет больше.

Ну ладно, про это потом еще поотвечаю.

Привет, вопрос с ребятами.

В чат Фастапе сбрасывал твой курс по Фастапе.

Говорят, очень плохая структура папок.

Пожалуйста, смотрите, давайте так.

Два момента.

В том видео, в той серии видео, которую я показывал, некоторые вещи я уже делаю иначе.

Я сам пересмотрел подход.

И если есть какие-то комментарии, пожалуйста, скидывайте просто мне в теле, в чат.

Только структурированно, типа не все говно, а... Типа вот здесь надо делать так и так.

Мне... Сейчас, давайте тогда, ладно, две минуты еще потратим.

По стапе, example, как там, best...

Как там?

Best Practices.

Вот мы открываем какой-нибудь фасад Best Practices.

Я покажу, что мне очень не нравится.

11 тысяч звезд.

Сейчас вам не видно.

Вот.

11 тысяч звезд.

Это много.

Это сильно больше, чем у меня всего звезд на всех моих проектах.

Это много.

Давайте смотреть.

Фасад Best Practices.

Смотрим.

Структура проекта.

Мне не нравится.

Что мне не нравится?

Давайте разбираться.

У нас есть SRC Auth.

Posts.

Смотрите, здесь модели свои.

Здесь модели свои.

Схемы здесь свои.

Здесь свои.

Что если у меня появляется... Во-первых, SRC.

SRC.

Здесь лежит Main.

Окей.

Хорошо.

А то некоторые еще не кладут сюда ничего.

Олимпик.

Почему Олимпик снаружи SRC?

Олимпик не касается моделей?

Так, окей.

Вот здесь, смотрите, глобальные модели.

А как я пойму, глобальная модель или в постах?

Схемы.

Как я пойму, это схема... Почему вот здесь модели есть глобальные, а схем глобальных нет?

Я не понимаю.

А что, если у меня схема ответа включает в себя вложенный...

Например, пользователь.

Да, у меня получается схема пользователя тут.

Вложенные посты пользователя.

Где эта схема будет существовать?

В рамках аут или в рамках пост?

Получается, из пост я... В рамках пост я импортирую из аут.

Короче, если у вас есть прям конкретные по моему коду комментарии, пожалуйста, приходите в Telegram-чат, пишите, я с удовольствием обсужу.

Я каждый день в чате.

Кто не видел, заходите в Telegram-чат, я каждый день там обсуждаю.

Отдельный чат для бустеров, там мы каждый день обсуждаем тоже...

И еще отдельный чат.

Для бустеров, кстати, на любом уровне.

Там за 200 рублей подписка, пожалуйста, приходите в чат.

И с любыми вопросами.

И еще отдельный чат по курсу.

И там отдельное обсуждение идет.

Там, конечно, люди некоторые пересекаются, но темы разные.

Короче, я с удовольствием отвечу.

Приходите.

Но вот здесь я не понимаю, а зачем мне это отделять вот так?

Хорошо, у меня будет relationship.

User...

с постами.

У меня, получается, будет импорт, кросс-импорт между пакетами.

Я думал, эти пакеты изолированы специально.

Мне тогда непонятно.

Ну, можно даже без импорта, можно строчку, но тогда они не так уж и изолированы друг от друга.

Окей, в Models что, в одном файле Models лежит три модели?

Я строго против.

На каждый класс свой файл, ну, питанечий файл.

Конфиг.

Что, на каждый сервис нужен свой конфиг?

Нет.

Короче, вот с этой структурой я очень не согласен.

Я ее часто встречаю.

Я ее не понимаю с практической точки зрения.

Для меня это непонятно.

Почему Олимбик не касается моего кода?

Он еще как касается, он зависит напрямую от этих моделей.

Почему мы его вынесли?

Вот если мы вынесли какой-нибудь...

Ну, вот здесь вот будет лежать, помимо gitignore, там dockerfile, dockerignore.

Это я понимаю.

Почему у нас requirements base.txt, dev.txt, prot.txt?

Кто в txt файлах сейчас хранит?

Пожалуйста, uv берем, берем poetry, берем ppn, пожалуйста, лучше, чем txt файлики.

Короче, если у вас есть комментарии, пожалуйста, приходите.

Я с удовольствием отвечу, с удовольствием обсужу.

Я пока просто искренне не понимаю, когда вот так вот разделяют.

Я не видел проекта, где я бы понял, почему так сделано.

Я видел проекты, где так сделано, я не видел, где я понял, почему так сделано.

Мне моя структура, которую я сейчас делаю, вот опять же на курсе, вот из самого свежего, да, что мы делаем.

Поставь URL shortener.

Вот мы начали с суперпростого, что даже на тестовом задании часто дают.

Как я делаю структуру здесь?

core-config, почему-то некоторые мне нравятся, я не понимаю, почему мне нравятся.

Опять же, пожалуйста, пусть объяснят, потому что они в другом месте не видели, а я в другом месте видел.

Вот, API, apv1, почему apv1?

Потому что обязательно будет apv2.

Мы надеемся, что не будет, но он обязательно будет.

Я сталкивался, делал на верхнем уровне, потом apv2, не структурировано получается.

Идем, short urls, пожалуйста, вот у меня views, тут detail views, list views.

Крут у меня отдельно, я люблю крут выносить в отдельную сущность.

Дальше мы переработаем, там, короче, разберемся.

Мне удобно, чтобы схемы были отдельно, и они были в своих файлах.

Да, тут в одном файле схем, сейчас несколько схем.

И так мне нормально, потому что я их все друг от друга наследую.

Но когда у нас тут будут схемы по юзерам, они будут в отдельном файле, а не в том же.

Модельки у нас пока еще нет.

Будут лежать в своих файлах.

Короче, вот эта структура, которая Best Practices, которая 11 тысяч звезд, мне просто непонятно.

Просто непонятно.

Если вы мне сможете объяснить как-нибудь там на, не знаю, на метапе мы с вами встретимся, вы мне расскажете, почему так, или в чатике напишите.

Я с удовольствием подключусь к обсуждению.

Sorry, мы это что-то затянули.

Вот, поэтому чужие слова передавать не надо, приходите, пишите, ну, как вы видите, своими словами.

Спасибо за ответ.

Вопрос еще по Джанго Ниндзя.

Что думаешь насчет него?

Очень похож на фастапе.

One Man Project, который поддерживается одним человеком, опасно использовать, потому что он в любой момент загибается.

Причем фастапе, это туда же на самом деле, но у него хотя бы есть комьюнити большое, но, например, мой мерч и квест уже года три не вливают.

Разница между Django 4 и Django 5 большая?

Да, сейчас Django 5.2 LTS, запускаем Django 5.

Чаще всего ругались на утилс, хелперс и кор.

Но спасибо за ответ.

Вообще, спасибо за фастапиограмм курс, очень помогло в изучении.

Круто.

Утилс, пожалуйста, называйте, как хотите.

Хелперс, называйте, как хотите.

Утилс и хелперс – это максимально размытое название для всего подряд.

У вас не будет в проекте все подряд.

Вы же не будете делать, например, вот у меня там есть, я люблю кейс-конвертер засовывать.

В стапе BaseApp.

Сейчас, все, две минуты и переходим.

Надо было чуть раньше начать.

Ну, окей.

Вот у меня в стапе Application, вот у меня здесь Utils.

Вот куда мне кейс-конвертер класть?

Мне что, под него заводить отдельный прям вот на верхнем уровне вместо утилз, да?

Создать кейс-конвертерс и внутри один-единственный кейс-конвертер.

Я не понимаю, зачем.

Поэтому я считаю, что здесь нормально.

Templates, ну как бы он к утилз относится или нет?

Я считаю, что скорее нет.

Чем да, но куда мне его деть?

Просто на верхний уровень, я не хочу на верхний уровень приложения закидывать, у меня тут и так много файлов.

Это все на верхнем уровне.

Run main, run main, create fastapi app.

Я бы его тоже куда-нибудь засунул, но он в утилс вообще никак не ложится.

Почему Alembic, например, вот в тех примерах снаружи торчит, я не понимаю.

Core, я сейчас объясню, откуда у меня Core пошел и почему я его придерживаюсь до сих пор.

Core — это, ну, я встретил на одном из проектов, где была монорепа для микросервисов.

Ну, микросервисов не в том понимании, как все мечтают, а в том понимании, как все делают.

А все делают так, что это одна кодовая база, просто разные деплойменты с одной кодовой базы.

Минус в том, что это все сломается, если где-то вы что-то сломаете.

То есть все сервисы сломаются, если вы сломаете что-то в общей части.

А плюс, что это очень легко поддерживать, ну, вот именно в таком виде деплоити, зависимости и так далее.

Понятно, что поддержка там, если мы что-то меняем, ну, не очень.

Так вот, если эти сервисы базируются на одном коде каком-то, то мы этот код складывали в одну папку, в кор, и там было куча всего, сильно больше, чем здесь, и этот код был сгруппирован в кор.

И у нас был запрет на импорт из одного сервиса в другой.

То есть у нас, например, сервис авторизации и сервис товаров.

Нельзя было из сервиса товаров импортировать из сервиса авторизации.

Условно, да, очень условно.

А в Core лежала моделька юзера, и с ней можно было работать.

То есть очень важно, как вы это у себя в проекте объясняете.

Вот здесь Gooney Corn, он не относится к API.

Модели, да, вот я сейчас модели выношу скорее из Core наружу.

Вот это вот привычка модели в Core сложить как раз-таки оттуда.

И схемы, то есть сейчас я их наружу кладу.

Но что это меняет в остальном?

Вот что это меняет?

То есть я не понимаю, то, что надо будет писать не from-schemas-import, а from-core-schemas-import.

Кто мне объяснит, что это плохо потому что?

Я прислушаюсь, может, буду там еще как-то рассказывать, что я был раньше неправ очень сильно.

Вот, все, окей.

Так, про это ответил.

Если что, приходите в чат, я с удовольствием поговорю про это все.

Что мы делаем?

Да, я закрыл, я хотел взять, где у нас тут, вот, взять вот этот пример, и мы сейчас пойдем на Django делать то же самое.

Поэтому мы стартуем Django, берем Django REST Framework, я беру PyCharm.

Сейчас беру PyCharm.

Так, у меня почему-то PyCharm от дока отвалился.

Вот, я беру PyCharm.

Возьмем example, тот самый app.

И...

Идем.

Так, это мы с вами все написали.

Я стартую новый проект.

Делаю файл new project.

И я создам это где-то рядом, где мы здесь создавали.

Давайте посмотрим.

Пвд.

Пвд.

Так я не настроил пока терминал себе красивый.

Вот сюда мы положим.

Просто я уже говорил, вроде я хочу другой инструмент использовать для настройки терминала, не как я делал в предыдущий раз.

Чтобы два раза не делать, пока откладываю.

Что мы делаем?

Мы называем это «example».

ДРФ movies catalog.

Каталогу Е можно написать, но зачем писать лишнюю букву, если можно не писать лишнюю букву.

Все, create new window.

И сюда же тащим.

Патчарм почему-то все время открывается на другом экране, не на основном.

Или наоборот, другой считает основным.

Подскажите, пожалуйста, как обрабатываете отключение клиента?

Ой, мне кажется, это в чате уже спрашивали.

В Go есть контекст, а в JS – борт-контроллер.

А в FastType ничего подобного не нашел.

Я не очень понимаю, это в какой момент обрыв.

То есть если пошел GET-запрос на получение данных, и вдруг он оборвался, ни разу не строил обработчик такой ситуации.

Если запрос оборвался, то это веб-сервер тот же Nginx обработает, а мы из нашего приложения просто дадим ответ, но пользователь его уже не увидит.

Если у вас какая-то более сложная логика, или если там какой-нибудь веб-сокет, ну тут уже надо смотреть.

Так, что-то мы с вами уже 20 минут болтаем.

Давайте мы начнем.

Значит, мы модные молодежные, мы используем UV, поэтому я пишу UV init.

Сразу же мы, как правильные пацаны, пишем python.gitignore python.gitignore и закидываем в... Ой, iPad блокирует экран, сейчас я его разблокирую.

Закидываем gitignore в...

Наш проект.

Сейчас я отключу автоблокировку.

Копируем этот файлик.

Идем в PetCharm, gitignore, обновляем, ID сразу же раскомментируем.

Почему-то GitHub до сих пор считает, что не обязательно ID.

Я считаю, обязательно.

Коммитим пока что только gitignore и называют initial commit.

Опять же, у кого-то другая практика.

Кто-то в первый commit сразу же весь проект запихивает.

Я не согласен, потому что initial commit, он корневой root commit.

И...

Если что, его поправить сложнее.

Можно тоже, но с дополнительными флагами, чем все остальные.

Поэтому зачем, если можно так сделать.

Так, и вот теперь я все остальное добавлю.

Скажу init uv project.

Или uv project, не так важно.

Это сделали.

Значит, что еще?

Я тут буквально сегодня на...

Записывал материал в программу свою образовательную.

Как мы работаем с pre-commit.

И поэтому я возьму отсюда pre-commit config.

Просто потому что... А, и uv.

Ой, uv.

Roof.

Я настраивал roof себе и рассказывал, почему я так настраиваю.

Поэтому я возьму себе roof-settings.

И я возьму себе прикоммит.

Просто чтоб сейчас не заниматься этим вручную заново.

Мы же хотим причёсанный код.

Так, вот это у нас пока не актуально.

Джанго надо будет включить.

Я здесь отключал джанго.

Джанго... Нет, руф.

Вот roof, как раз еще даже вкладка осталась открытая в другом окне.

Django.

Сейчас пока загрузится.

Добавим и возьмем pre-commit config.

Это просто, чтобы мне сейчас было удобнее вести разработку.

Так, значит, uv add –dev pre-commit roof.

Black не будем, наверное, ставить.

Так.

Хотя нет, почему?

Но он у меня глобально есть.

Да, пока не буду ставить, я его просто активирую.

Ой, видели, как он смешно?

Это маг такие анимации строит.

Зачем он сделал... Ой, ладно.

Так, black.

Берем black, binary, code format.

И... Да, все окей.

Пока трансляция не работает.

Опа, спасибо.

Сейчас посмотрю.

Вы в эфире.

Чтобы завершить трансляцию, трансляция еще не началась.

Ничего себе.

А в чем беда?

Час.

Ничего себе.

Короче, спасибо большое, что написали.

Он прям пишет, у вас еще не идет трансляция.

Хрень какая-то.

Сейчас я перезапущу.

Спасибо большое, что написали.

Блин, реально нужен еще отдельный человек, чтобы это все мониторить.

Был эфир в ВК, то есть он просто куда-то сломался.

Опубликовать.

нет давайте сейчас секунду так сейчас я заново запущу трансляцию именно в vk да я вот генерирую новый ключик прям чтобы прям все точно было запускаю заново эфир в vk и

Опа, тут же все полетело.

Тут же.

Просто моментально.

Короче, блин.

Трансляция в ВК.

Притом, что шла в ВК трансляция.

Я проверил, везде была трансляция.

Везде была трансляция.

Ладно, специально для ВК мы просто создали новый проект.

Я скопировал сюда готовые настройки.

Все, спасибо большое, что написали.

Блин, капец, конечно, им еще работать и работать над этим.

Так, ну, на платформе, понятно, никто не пишет.

Главное, что на платформе вот ничего не сломалось.

На Рутубе тоже ничего не сломалось.

Окей.

Спасибо, что написали, спасибо большое.

Сейчас в тележке проверю, что в тележке все ок.

Ну, 6 участников даже зачем-то в Телеграме смотрят.

Я соболезную тем, кто смотрит в Телеграме.

Да, в ТГ звука нет Блин, а у меня звук в Телеграме есть?

Сейчас я проверю Есть Есть Так, проверим еще раз Трансляция приостановлена Почему?

Почему трансляция приостановлена?

Что это значит?

Вот смотрите Вот как я это вижу

Как я это вижу?

Вот так.

Вы в эфире, чтобы завершить трансляцию, бла-бла-бла.

Давайте я вот здесь закрою еще раз.

Обновлю страничку.

Вот, смотрите, эфир идет, лайв, да?

Трансляция приостановлена.

Куда вернется?

Я не отходил, я здесь.

Так, сейчас тратим еще 2 минуты на это.

Что в ВК может не нравиться?

Битрейт?

Нормально.

Десятку я всего поставил, это немного.

Ммм.

Сейчас я настройки открою, чтобы ключики не спалить.

Открою отдельно.

Еще.

Редактировать я нажимаю.

Так.

Настройки трансляции.

Давайте я сейчас еще раз запущу заново.

Я просто не понимаю, в чем может быть дело.

ВК.

Отключаю эфир.

Указываю заново.

RTMP.

Такой-то адрес.

Да, это в ВК-шный адрес.

Дальше я копирую ключ к трансляции.

Я вставляю его в стриминговую.

Снова новый ключ.

То есть он каждый раз генерирует новый ключ?

Сохраняю.

Закрываю.

Говорю «Сохранить».

И запускаю стрим на ВК еще раз.

Сейчас, может, у меня где-то открыта еще страница с ВК, и я поэтому... О, снова ВК пошел.

Вот, смотрите.

Вот, идет.

Я ничего не делаю.

Давайте так.

Ничего не делаю.

Просто отключу звук, чтобы не было дублирования.

Эфир идет.

Вот, я показываю руку, например.

Ну, сейчас ВК страница должна появиться здесь.

То есть я просто перезапустил еще раз, посмотрев настройки, еще раз скопировав данные.

ВК отваливается почему-то.

Вот сейчас посмотрим, отвалится заново или нет.

Я ничего не меняю.

Ничего не меняю.

Вот пока идет эфир.

Пока идет.

Ну вот, да, двигается, все нормально.

Сейчас я проверю, что у меня нигде вкладок с ВК больше не открыто.

Видеозаписи.

Нет, только это.

Вот пишу vk.com.

Нет, у меня все вкладки открытые.

Здесь и здесь нет.

Здесь нет.

То есть здесь все окей.

Вот, ну пока идет.

Короче, ВК очень странно себя ведут.

Открываю OBS.

Очень странно, очень странно.

Я буду мониторить пока, если отвалится снова.

Вот, но пока, пока идёт.

Sorry, придётся в следующий раз ещё раньше начинать.

Ну, ВК очень странный.

Что, почему отвалилось?

Типа, что случилось?

Так, что мы тут делали?

Да, я хотел, чтобы мы руф правила посмотрели.

Джанго.

Вот, есть Flaygate, Джанго.

Вот это я хочу активировать правило.

Потому что, ну, там приложение на фастапе, нам не нужно было.

А здесь нам нужно... Где это у нас?

И m вот здесь поставим.

Так.

И все.

Значит, сделаем.

Теперь pre-commit run.

Он проинциализирует в первый раз быстро довольно-таки.

А, или мы уже делали.

И...

В чем дело?

Мы говорим, что мы поставили это все.

UV-Log мы еще не коммитили.

Сейчас закоммитим.

Значит, мы поставили... Не поставили.

Мы делаем UV-Add.

Руф, странно, я же написал это вроде, минус-минус деф, а он может вниз добавил, да, dependency, нам не надо так низко, вот сюда, пожалуйста, вот прикоммит и руф, все, есть, и то руф можно было глобально поставить, ну ладно, коммитим, коммитим.

Так.

Install.

Так.

Install.

Pre-commit.

Пока в ВК идет трансляция.

То есть просто почему-то она отвалилась два раза подряд.

Почему?

Кто его знает.

Так.

Пока что, с учетом даже всех замедлений, YouTube стабильнее всего.

И комменты вы тоже пишите.

То есть проще, казалось бы, зайти на YouTube и написать, что что-то не работает.

Но нет.

В Telegram все хорошо.

Ну, отлично.

Так, ну все, тогда приступаем.

Значит, что нам нужно?

Нам нужно поставить Django.

UVM add Django.

И принципиализировать новый проект.

Пока что без Django REST Framework.

Пойдем, пока скачается Django.

Все, все окей.

Django.

Давайте так.

Python-m Django.

Start project.

Movies.

Catalog.

В include вроде не тот пакет указан.

Include.

Где?

SRC.

А, SRC, да, спасибо большое.

Мы сейчас это укажем.

Вы абсолютно правы, SRC.

Да, потому что вот мы сделали новый проект, мы из каталога, и вот это у нас будет нашим корнем проекта.

Мы это укажем вот здесь.

Давайте мы сразу же напишем, что мы проинциализировали проект.

Нам тут ничего менять не надо.

Да, на старте мы ничего не меняем.

Юзер у нас будет стандартный.

SGI не трогаем.

ManagePy.

Окей.

Да, все, все окей.

Давайте мы напишем, что мы проинциализировали проект.

Группировка обязательно по папкам, чтобы было легче.

И мы говорим install django.

Давайте отдельно.

install django, но тогда нам только вот это пока.

install django.

И теперь мы еще делаем init django project.

init django project.

Все, сделали.

Прекрасно.

Мы сделали проект.

Ну, запустили именно... Создали Django проект.

Давайте проверим, что у нас вообще стартует.

Но тут я не думаю, что будут проблемы.

Нам надо будет подключить это к Postgres тоже, чтобы не со SQLite мучиться.

Python... Нет, мы переходим в movies каталог.

И теперь python managepy runserver.

Девелопмент сервер, бла-бла-бла, это мы все знаем.

Проверяем.

И, конечно же, конечно же, ссылку надо открыть не в том браузере, который мы последним тыкали, а в том браузере, который просто захотелось.

Вот, открыли.

Короче, все окей.

Все у нас есть.

Django 5.2, прекрасно.

И что мы делаем дальше?

Мы проверяем, идет ли VK-трансляция.

Идет все нормально.

Почему слетело тогда?

Ну ладно.

Все.

И что мы делаем?

Мы для начала заведем модельки просто, которые у нас есть уже в нашем проекте, где можно будет посмотреть итоговую репу.

На GitHub выложу.

На GitHub выложу.

Я закину в описании к трансляции ссылку, но на GitHub будет.

Так.

Давайте мы еще настроим Django проект.

Вы же все используете PyCharm Professional, поэтому мы сразу же используем вот здесь интеграцию с Django.

Project root.

Project это у нас... Где мы сейчас находимся?

Ой, PyCharm просто... Почему бы не открыть просто текущий проект?

Ну, типа, вот текущий проект, ты уверен, что это он?

Я такой, да, уверен.

Нет, он просто открывает какую-то папку.

Короче, проще так указать.

ManagePy видим, Settings.

Ну, должен был увидеть, но он почему-то не видит, что здесь Settings лежит.

Вот он, Movies Catalog, Settings.

Или я неправильно указал?

Project, да нет.

Нет, ну сейчас посмотрим, как он отрезолвит.

Admin пока ничего нет, моделек нет, views нет.

Окей, сейчас посмотрим.

И что мы делаем?

Мы стартуем приложение.

Давайте поймем, как у нас будет выглядеть.

Вот мы делали здесь описание, делали модельки.

У нас пара моделек всего, да?

Так, модельки, вот.

AgeRating, моделька.

Genre.

моделька и ой movie movie я тут опечатка кстати надо это поправить давайте мы это сделаем в патчарме очень удобно нажимаем shift f6 movie genre и рефакторинг вот эти все галочки стоят рефактор бац смотрим commit что поменялось поменялись все импорты все потрясающе а это чё

А, нет, это не нужно.

Это я проверял.

Это я проверял, как мы стриминг делаем в асинхронный стриминг.

Короче, все окей.

Большой файлик писать, чтобы долго, если можно было, чтобы нормально, короче, все окей.

Это не касается.

В этом плане movie тут никак не меняется.

Да, все окей.

Rename модуль fix type опечатка.

Так.

Что не нравится?

Порядок поменялся.

Смотрим.

Это поменяли, это поменяли, это поменяли, это поменяли.

Все, все окей.

Пуш.

Идем в модельки.

Смотрим.

Значит, самое главное, что у нас?

Это фильм.

Мы начнем с фильма.

Но у нас будет одно приложение.

Тут нам не нужно несколько приложений, потому что жанр и ограничение по возрасту касается тоже одного.

Поэтому приложение мы называем... Вот смотрите.

Да, опять же, откуда мы берем инфу?

Как же мне называть что-то?

Да тут все написано.

Вот мы создаем проект.

MySite.

JunkZutorial.

MySite, конечно, плохо называть.

Не надо так делать.

Я так делал тоже, но не надо.

Бла-бла-бла, бла-бла-бла.

Это все неинтересно.

Приложение.

Вот.

Полз.

То есть у нас опросники, у нас фильмы, поэтому мы называем MovieYes.

Я иду в наше приложение.

И я пишу PythonManagePy.

StartAppMovies.

Все, то есть это то, что касается фильма.

Смотрите, тут мне, если уж мы пилим что-то нормальное, мне не нравится, что Django считает, что нормально в модул складывать несколько классов.

Почему мне это не нравится?

Потому что...

Я встречал проекты, где в этом файле тысячи строк, две-три тысячи строк.

Это больно.

А там может быть 10 моделей, например.

И как бы на 10 моделей 2000 строк, ну по 200 строк на модель, учитывая, что там методы всякие, это много, но не так, чтобы много.

Вот если бы это были файлики по 200 строк, было бы нормально.

Поэтому я предпочитаю вот здесь, если мы делаем по-нормальному, если мы тратим на это время, если мы реально собираемся развивать проект, поменять на Models пакет.

Я говорю, да, это все мы добавляем, вообще все добавляем.

Command Option A, говорю, добавить, пожалуйста.

Вот, и в Models мы уже будем создавать.

Например, у нас будет новый файлик Movie.

Так, movie, добавляем, сейчас посмотрим, я не помню, только в init надо добавить или нет, но сейчас разберемся.

И давайте мы пока без movie закоммитим, все остальное мы не трогаем, все как есть, так и оставляем.

И пока что он мне ничего не видит, да, потому что мы настройки не обновили, конечно же, нам надо настройки обновить.

Это у нас Settings.

Мы просто берем... Я предпочитаю... Да, кстати, во-первых, правой клавишей мыши Mark Directory S Sources Root обязательно для Django.

Вообще для проекта, где у нас... Вот тут тоже я так делал.

Мы из каталога, у нас Sources Root.

Потому что отсюда мы будем импорты делать.

И я беру Apps.

Apps.

Беру Movies Config.

Copy.

Не видно вам ничего, конечно же.

Очень удобно.

Правой клавишей мыши.

Copy.

Вот.

Copy Reference.

Иду в настройки.

мы идем в settings и ставим приложение приложение у нас ставится вот здесь installed apps вот тут у нас будут сайт packages сайт packages и

И тут будут first party, то есть мои.

Ну, давайте my так и напишу.

Вот movies.apps.movies.config.

Все готово.

Ну-ка, отрезовывается ли здесь?

Вот, отрезовывается.

Все, movies есть.

Hello, deaf people.

Hi.

И мы делаем commit.

Что мы скажем?

Что у нас migrations?

Да, все окей, все окей, все окей, все окей.

Register models here — это для админки.

Ну, админку тоже можно так в пакет превратить, но пока не будем.

Apps не трогаем, tests не трогаем.

Tests обязательно в пакет надо будет превратить, мы сегодня тесты писать не будем.

Views, посмотрим.

Settings.

Все, установили.

Init Django App Movies.

Камид.

Привет из Анталии.

Прекрасно.

Как у вас там?

Тепло, солнечно?

А то... Вот в Москве... Привет, кстати, всем любителям глобального потепления.

Привет.

Всю неделю снег, холодно, если что, середина апреля.

Без пары дней середина.

Всем привет, хорошего стрима.

Спасибо большое, да, всем привет.

Так, значит, что мы делаем?

Чекаем, что вы больше не писали, что есть проблемы, да, все окей.

И приложение создано, нам надо создать модельку.

Опять же, я не буду сейчас заново изобретать модельку, мы возьмем описание, чтобы отсюда не копировать, да, и по этому описанию пойдем.

Пу-пу-пу.

Вот описание.

Бла-бла-бла.

Таблицы.

Вот таблицы.

Короче, я возьму этот ридми.

А, у нас там уже ридми есть.

Его UV сгенерил.

Пустой, правда, но нам нормально.

И мы просто берем вот эти вот свойства.

Закидываем и начинаем.

Фильм ID автоматически будет.

Кстати, на Begin давайте поменяем.

Мы же можем еще в настройках это поменять, если тут еще нет.

Да, нам надо Postgres подключить.

Вот, что мы еще не сделали.

Так, Settings.

Во-первых, да, BigAutoFill, все здесь окей.

Так, идем просто в доку сейчас, чтобы не выдумывать ничего.

Подключаем Postgres.

Так, Postgres.

junk trip postgres ну тут же будет пример как этим пользоваться нет тут только структурка use examples вот вот мы хотим использовать postgres нет а не aggregation а просто postgres нет aggregate functions это все про aggregate как мы его подключаем

Да, конечно, печально, что сложно найти нормально через их доку.

Вот, Postgres.

Вот.

И мы что берем?

Мы берем PsychoPG 3, то есть просто PsychoPG.

Устанавливаем.

Я делал ролик на YouTube, он лежит, по-моему, уже.

Если нет, ну, наверное, лежит на YouTube.

Как правильно эти настройки хранить?

Мы их просто в Env засунем.

Просто сейчас не будем париться с этим всем.

Я это уже все рассказывал.

Мы засунем все это в Env.

Поэтому что я делаю?

Я иду в мой Django...

To do project.

И я беру отсюда.

Вот был pgservice.conf, но... Да.

И пароль.

Пароль я отдельно закидывал.

Сейчас посмотрю.

Удобно, когда ты уже это делал, и можно просто заново подглядеть, как это сделать.

И мы смотрим, как я подключаюсь к базе.

Короче, geten я все сделал.

Ну, ладно, давайте так же сделаем, что нам.

Databases.

Вот это берем.

Здесь у нас databases есть уже, да?

Да.

Это у нас идет под нож.

Все в git-истории есть, мы можем это, если что, восстановить.

Берем эту часть.

Алло, вот black, конечно, отформатировал.

Спасибо.

getelf, import.

И...

Есть, конечно, классный инструмент для работы с этим, но ладно, сейчас не будем делать.

Мы сейчас это как сделаем?

Мы сейчас будем запускаться через PyCharm, и поэтому у нас эти переменные будут в окружении.

И как мы это сделаем?

Мы можем сделать так.

Create, так, Edit Configurations, плюсик.

У нас тут Django уже, по идее, так мы настроили должно автоматически.

Так, давайте...

RunServer.

Да.

И вот переменное окружение.

Переменное окружение у нас будет NameUser... NameUserPassword... А, слушайте, зачем?

Я сейчас здесь... Нет, не хочу так.

Ну, хотя ладно.

Короче, я сейчас вот эти все параметры вобью.

Как дефолт.

Только это не ToDoManager, а MoviesCatalog.

Здесь у нас будет App, например.

Вот.

И, конечно же, на продакшене у нас будут другие значения.

Но сейчас мы прямо это и вобьем.

Нам нужен, получается, Postgres.

Мы его запустим просто из docker-compose.

Поэтому я копирую содержимое.

Нам даже все не нужно будет, но мы сейчас сделаем, что нам надо.

docker-compose.compose.

компост .

яму что такое не попадаю яму .

минском после яму да мы все добавляем в гид пожалуйста мне следов гид игнор нет погода то мы сохраним pg есть у недавно кстати упаковывал через юви

В докер используем UV, что-то я там чуть ступил, но разобрался.

В общем, не сложнее, чем в спойтере, только UV все равно принудительно создает виртуальное окружение, но нашел способ как с этим тоже жить.

Просто я считаю странным делать внутри докер-контейнера, который сам по себе окружение изолированное, делать еще одно изолированное окружение, виртуальное окружение питания.

Поэтому, когда работал в спойтере, я просто отключал.

Но UV смотрит на это иначе, но там тоже несложно обойти.

Так, все указали.

Все указали.

Здесь мы укажем, конечно же, те же самые настройки.

Moves Catalog, App, SuperSecret Password.

Moves Catalog, App, SuperSecret Password.

И давайте запустим, проверим.

Докер у меня вообще стартовал.

Докер.

Мы перейдем в новый терминал.

Да, здесь нам надо сделать docker-compose.

Во-первых, пул, чтобы мы стянули, если у нас... Ой, почему же у нас 4 нет?

Стой.

Я хочу 17.4.

Уже есть 17.4.

Да.

О, да.

17.4 есть, да.

Поэтому мы сейчас его возьмем.

Вот делаем docker-compose-pool.

И мы делаем docker-compose-up-d. Запускаем Postgres.

Все.

Какое наибольшее количество атрибутов для модели какой-то сущности ты видел?

Больше сотни было?

Было больше сотни.

Я видел... Ой, это вспоминается мем.

Ну и мем.

Отрывок из «Бегущий по лезвию».

Ой, никогда не вспомню.

Там такая замудренная цитата.

Я... Так.

Blade Runner.

I saw things.

Вот.

Короче, видал, видал.

Печально это все, когда делают... Делают кучу всего.

Короче, можно иногда и подекомпозировать чуть-чуть.

Ну, ладно.

Так, все, запустился Postgres.

Давайте проверим docker-compose-ps.

Так, что у нас тут?

Минуты go, up, healthy.

Все, все хорошо.

Health check мы тут делали отдельно.

Опять же, про это все были ролики, поэтому сейчас не паримся.

И надо закоммитить.

Раз у нас работает, мы коммитим.

Пока что мы коммитим только, только docker compose create docker compose for pg.

Так, теперь.

Здесь у нас будет, да, конфиг, конфигуре app for, давайте, project for pg.

Только надо движок будет поставить сначала.

Поэтому мы сделаем так в терминале.

Привет, Сурен, привет.

uv add

PsychoPG.

Это третий PsychoPG.

Вот он в третьей версии поставился.

Мы здесь сначала сделаем так.

Install PsychoPG.

Да, мы поставили psycho.pg.

Install psycho.pg.

У нас поставилось все.

Теперь мы делаем вот здесь вот configure project for pg.

Вот, и теперь мы можем модельку создавать.

Давайте закроем все.

У нас будет, короче, вот это я сейчас возьму.

Мы идем в movie.

Ой, а movie зачем я закоммитил?

Где это было?

Вот, невнимательно коммитил.

Где это было?

Где это было?

Вот здесь я закоммитил, а не надо было.

Что можем сделать?

А мы можем сделать вот так.

Interactive rebase from here.

Вот это stop to edit.

Да, start rebasing.

Я просто дропаю отсюда.

Delete.

Delete.

Делит.

И говорю, что мы это amend'им к текущему коммиту.

То есть вот commit, где был models создан, я говорю amend.

Все, continue.

А что, где?

Короче, continue.

Да, в смысле...

amend.

Вот.

А, он там, видимо, меня поправлял этим.

Короче, continue.

И все у нас случилось.

Да, единственное, что у нас нет файлика снова, но если нам надо было, мы могли его забэкапить, либо из истории его взять можем.

И теперь вот этот initial gap у нас модул спусто.

Все.

И теперь я создаю новый

файлик.

Называю в честь единицы экземпляра, то есть не movies, а movie.

И здесь у нас пока что будет такой docstring подсказка.

Сейчас разберемся.

Значит, мы создаем класс movies

Ой, from use.

From djung.db.

Import models.

Мы делаем models.model.

И класс мета.

Сразу же создадим.

Нам пригодится мета.

Например, order.

Ordering.

Ну ладно.

Ордер у нас по ID будет.

Просто сразу же указываем все, что нам надо.

Пока что больше ничего не надо.

И мы описываем поля.

Title.

Значит, я хочу CIText.

Как там у нас CI?

Как там?

Models.

Сейчас мы найдем.

Раз уж мы делаем такое, то, во-первых, давайте напишем Django CIText.

Примерчик.

Не, неужели для этого отдельный пакет надо ставить?

Мне кажется, я как-то этот вопрос и решал.

Что, прям надо пакет ставить?

Блин, серьезно?

Вот, Contrib.

А тут, подождите, сейчас, секунду.

Пять дней назад, то есть недавно обновляли.

junkdb, modus, бла-бла-бла.

Вот, сайт текст был.

junk, contrib, postgres, fields.

Ну-ка, from jungle, contrib, postgres, import.

Нет, postgres, fields, import, сайт текст.

Ну вот, а что он мне там?

Ой, блин.

Еще, конечно, Google молодец тут на страничку.

Почему 5.0?

Почему не 5.2?

Как мне попасть на актуальную?

Почему документация?

Вот, 5.2.

Понаделают

Пожалуйста, все есть, только это просто Release Notes, но оно существует.

Пример бы привели.

Ни одного примера.

CITextField.

CIText... вообще нифига.

Ладно.

Он у нас как обычный TextField, поэтому мы просто...

А, except removed for support historical migration.

Все понял.

Все ясно.

Так написали бы, что он removed.

DB collation with a case insensitive non-deterministic collation instead.

Давайте.

Что-то я, видимо, это... Древний.

Model field reference.

Case insensitive.

Так.

Че?

Так, понятно, ладно, все, не паримся, берем.

Не просто так существует этот проект.

17 звездочек, блин, он, наверное, существует два дня.

А можно мне... Так, Django, еще раз, CI, текст.

И я хочу просто для Postgres CI текст.

Я делал модельку для ноутбуков своего проекта, там 33 было, аж глаза разбегались, чтобы за этим всем следить.

Как следить за сотней плюсов?

Может быть... А нельзя было сделать это... Надо подумать.

Нельзя было сделать это типа ноутбук и набор свойств, как отдельная модель.

Но иногда это не нужно, иногда это неправильно, потому что проще... Проще все в одну кучку сложить.

Короче, мне не хотят подсказывать.

Как будто бы с алхимией было проще.

Что в разнице с обычным текстом?

Я хочу, чтобы у нас название было уникальным, независимо от регистра.

Чтобы нельзя было создать фильм с названием «Начало» с большой буквы, «Начало» с маленькой буквы.

Это было бы два фильма.

Сейчас, на самом деле, для примера это вообще не нужно.

Но я хочу... Так, «Джанго».

db collation джанго модел филд референс вот бы мне кто-нибудь подсказал тут нормально ну и что сюда что запихивать то hint use text field db collation with case sensitive non deterministic collation instead давайте вот это мы сейчас засунем вот

вот вот недавно все пару лет назад нам рассказали как с этим быть 51 вот нам говорят слушай делать так хорошо все это все вот релиз но вот здесь где-то это сносили я даже пропустил ну-ка сяй текст deprecated на ok и

Вот, например, для имейла, кстати, это актуально.

Понятно, они хотят, чтобы я прямо в Postgres создавал коллэйшн.

Прямо обязательно, да?

Ладно, издеваются надо мной, издеваются.

Ладно, давайте не тратить на это время.

Maybe drop.

Короче, с алхимией было проще в этом плане.

Я сейчас не буду с этим разбираться, чтобы мы потратили на это полчаса, и потом в конце опять суетились, бежали.

Сейчас используем обычный TextField.

Значит, забили на это.

Все.

Смотрите, как вот Django нас ограничивает.

Title.

Это будет Models.

точка char field max length для названия сколько мы там делали 200 120 150 достаточно description пусть будет text field

Blank true.

Null false.

То есть blank туда можно пустую строчку положить, null нельзя положить.

Release date.

Null true.

Blank true.

То есть можно не заполнять.

Duration.

Integer field.

Тоже может быть неизвестно нам.

Но у нас есть positive integer field?

Ну-ка.

Positive integer field.

Вот.

Потому что у нас не может быть...

Ну ладно, пусть будет 0.

Хорошо, минуса не может быть.

0 пусть будет.

Ладно.

AgeRating.

Это у нас будет ссылка.

Внешний ключ.

Мы его сделаем потом.

Все, мы сделали новую модельку.

Смотрите, хорошо бы сделать хотя бы string.

И сделаем, да, конечно же, devstr return self-title.

Вот так.

И теперь мы идем...

Так, смотрим.

Давайте мы add readme.

Add models descriptions to readme.

Добавь валидатор поля в сервизаторе и там сделай lower.

Да, кстати, нормальный вариант.

Только нет, смотрите.

Это при сравнении на то, что он существует.

Кстати, unique я не поставил.

Title, index.

А unique я... А в прошлый раз мы unique сделали.

Сейчас, секунду, movie.

Нет, это схема.

Моделька movie.

120 вообще делали, индекс делали, а схему... Ой, а юнит не делали.

Ну и ладно тогда вообще, пофигу.

А мы здесь где-то CI сделали в итоге?

Нет.

А что я тогда парюсь?

Я думал, что он здесь CI будет.

Ладно.

Я хотел просто сделать прям как в алхимии.

Пусть в алхимии, сейчас сделать несложно.

Окей, 120 пусть будет, как и там.

И мы делаем его индекс.

dbindex true.

То есть, что на стороне баз данных, надо сделать индекс, чтобы мы по нему искали потом.

По описанию тоже можно бы искать.

Кстати, мы здесь делали.

Мы здесь не делали.

Ну ладно, пофигу.

Пока так.

Таблица.

Так, это models description to readme.

Добавили.

Мы создаем модельку.

Давайте перед тем, как ее коммитить, мы сделаем django python-manage-py.

Make Migrations.

Improperly Configured Field.

Psycpg.

Где мне надо указать Psycpg?

Engine.

А я не указал?

Идем в Settings.

А что нам раньше не сказали?

Settings.

Engine.

Вот он.

DjangoDB.

Backends.

PostgreSQL.

А что?

Надо сказать, что я хочу писать КПГ, а он не нашел писать КПГ.

Мы же его ставили.

Смотрим.

Dependency Jungle, писать КПГ.

Чего ему не нравится?

Сейчас разберемся.

Привет, смотрю твои видосы с недавнего времени.

Благодарен тебе за то, что ты доносишь все очень понятно.

Супер, я очень рад.

Пожалуйста.

Ладно, просто берем, копируем, вставляем.

Stack Overflow Driven Development.

Что такое?

Binary.

Ну, сейчас я проверю вообще в целом.

Давайте сделаем так.

Python.

ManagePy.

Shell.

Хорошо, просто Python.

Import.

PsychoPG.

Ага, понятно.

Ставим Binary и все.

Мы ставим UV, Add, PsychoPG, Binary.

Я что-то думал, что я уже решил вопрос с этим.

Ну ладно, все, Binary есть.

Все, теперь живем.

Проверяем.

Shell.

Нет, нет, не ты.

Shell.

Да, все живое.

Может FD в зависимости указать.

Давайте это в dev-зависимости укажем.

То есть я хочу сказать, что у нас... Так, сейчас.

Минус-минус dev-psycpg-binary, а просто psycpg у нас будет основной.

То есть если мы в контейнер собираем, там нам не binary надо, а собрать под нас.

Вот так.

Все.

Прекрасно.

То есть мы просто локально хотим binary, чтобы был.

Запускаем shell.

Все, живем.

Отлично.

Так, значит, здесь мы говорим, что у нас binaryPsychoPG, binaryPsychoPG for...

local dev.

Забавно, что там просто try-accept, и когда происходит ошибка при импорте, а там ошибка при импорте, что у нас не собрано, то мы просто получаем ошибку, что типа нет как будто бы этого пакета, а на самом деле мы его импортировать не смогли, потому что он неправильно установлен.

Короче, забавно.

было какое-то сообщение написано message retracted это вы типа его отменили случайно опечатали случайно отправили бывает ты не используешь ipython для shell удобно очень я очень редко так запускаю если мне надо запустить python в интерактивном режиме я запускаю вот здесь на самом деле в PyCharm а тут уже довольно интерактивно то есть я пишу здесь видите сразу подсказки есть но это очень редко потому что я заметил что когда вот так вот делаешь потом надо отредактировать что-то и приходится заново набирать поэтому я просто поддерживаю у себя файлик вот сейчас покажу я это тоже в проекте показывал

Я поддерживаю файлик у себя, став, я в нем пишу что угодно и запускаю его.

Почему это удобно?

Потому что у него сразу зависимости нужны мне, мои конфиги сразу же здесь есть.

Если я что-то поправлю, вот я здесь хочу просто все заново проверить, но только поменять decode responses на false.

Все, пожалуйста, очень легко, запускаю заново и все.

Поэтому я в целом в интерактивный Python довольно редко залезаю.

Так, и мы делаем make migrations.

Смотрим.

No change detected.

Почему?

Потому что мы init не заполнили.

Да-да-да, это я не сделал.

From movies.models.movie.import movie.

As movie, кстати, можно сделать, чтобы это было для экспорта.

Вот.

Как на это, кстати, среагирует руф, посмотрим.

Там может быть правило, которое не в курсе о том, что нам здесь это надо.

Но мы можем тогда на models, на все init такое правило разрешить.

Так, сгенерили миграцию, смотрим.

Проверяем миграцию обязательно своими глазами.

initial, blah, blah, blah, operations, movie, id, title, description, duration, так, id, big, autofield, ok, options, ordering, id, окей, пока что вопросов нет, коммитим, делаем коммит,

Читаем, да, что мы сделали.

И, значит, давайте знаете, что сделаем.

pre-commit, не здесь, pre, а хотя можно было здесь, ну ладно, commit run.

Что он мне скажет?

Да, что-то он мне говорит.

Значит, Django 0.12, смотрим правила.

Order of models inner classes meets and fills doesn't fall Django style.

А, да.

Я люблю, конечно, метакласс сверху, но, окей, раз у нас такое правило по стилю, которое я не знал, то, пожалуйста, пусть будет здесь.

Давайте проверим еще раз.

А, ну да, надо все добавить, все добавляем в отслеживание.

Commit run.

А, ну потому что здесь tuple должен быть на самом деле, просто вот так.

И все.

Сейчас вот так вот делаем.

И вот, да, ему не нравится import alias doesn't rename original package.

Вот это.

Мы сейчас это заигнорим, потому что это у нас для экспорта обозначения специально.

То есть, когда мы делаем as то же самое, так алхимия, например, делает, и мы же не считаем, что алхимия плохо написана.

Вот мы идем в алхимию.

Бац, смотрите, compiled as compiled, connection as connection.

Чтобы all не поддерживать, как я вот файлик all завожу, здесь, чтобы этого не делать, мы сейчас пойдем...

в pyproject.oml и скажем, что у нас perfile ignores models то есть получается что угодно models slash init

init.py равно и мы вот здесь игнорим смотрим как она называется импорталис бла-бла-бла это мы просто комментируем смотрим прокатит ли так все выбираем pre-commit run бац

То прокатило.

Он мне еще будет на миграции ругаться?

Нет, пошел вон.

Майгрешность вообще, значит, на вот это правило не проверяем.

Ну, короче, видите, руф вызывает боль, боль и еще страдания.

Ну и боль.

Значит, вот это мы выкидываем отсюда.

Вот так.

Так.

И надо просто указать путь.

Значит, что угодно.

Дальше migrations.

Дальше чтоугодно.py.

Мы игнорим.

И проверяем.

О, все, живем.

Не так уж сложно было под нас настроить.

Все потрясающе.

Идем коммитить.

Значит, что... А, да, давайте проверим миграцию.

Мы делаем... Так, python managepy migrate.

Бац, все, живем.

Все есть, работает.

Наше приложение movies-каталог.

Да, movies, точнее, приложение наше.

Все есть.

Значит, все работает.

Мы идем это коммитить.

И я говорю, что...

Extra roof configs for models and migrations.

И... Models...

Да, createMovieModel.

createMovieModel.

Так, теперь мы добавим его в админку, чтобы нам было легче за этим следить.

Как мы добавляем в админку?

Мы говорим admin, register, movie, класс movieAdmin, дальше listDisplay у нас тут, ой, movie, title, description, releaseDate, duration, id тоже,

Так, четыре штуки.

Вот так, значит.

Так.

Вставляем.

И...

Кстати, можно это убрать или переносы добавить.

Давайте переносы добавим, потом у нас поля будут появляться, чтобы гид фандализма не было.

Лист дисплей.

Лист дисплей links у нас будет ID и title.

Дальше у нас лист фильтр по title и release date.

Search fields точно так же.

Подождите, а в чем разница?

сейчас, а, это если у нас search fields, это если мы поиск делаем, да, именно там, вот так, да, все, окей, годится, и погнали, запускаем, у нас рансервер вот здесь есть, стартуем, переходим в браузер в этот раз куда надо, docs, значит, у нас здесь, ой, docs, админ, значит, у нас здесь не с кем зайти, потому что мы еще не создавали юзера, но мы сейчас очень легко сделаем, python managepy,

Create super user.

Дальше нас спрашивают, кто я говорю, админ.

Он меня спрашивает почту, я говорю, не знаю.

Пароль очень надежный, я говорю, точно, я уверен.

Он говорит, все создано.

Заходим с админом.

Все потрясающе, movies есть.

Покажите мне, как быстро вы на фастапе делаете админку.

Так, movies есть.

Давайте, что мы сделаем дальше?

Создавать мы будем тоже по API, поэтому мы сейчас для начала создадим все сущности... Да.

Нет.

Мы сейчас прикрутим API, а потом создадим новую сущность, прикрутим туда API тоже.

Значит, что мы делаем для этого?

Для этого мы подключаем Django REST Framework.

Django REST Framework.

Да не лого, а просто REST Framework.

Лого это мне было... Ой.

Хм.

какую-то кнопку нажал, и у меня пошла запись.

Ха.

Я себе когда-то, видимо, настраивал на клаве горячую клавишу, чтобы у меня была отдельная кнопка для старта записи, а я забыл об этом уже.

Надо это потереть.

Давайте я покажу, как я это делаю.

Я захожу на USB, у меня клава подключена по USB.

Я говорю Authorize, говорю, да, вот эту текущую клаву.

И... Так, второй уровень, ну, первый в смысле.

И вот здесь у меня M0, то есть у меня здесь...

Нет, подождите, на первом уровне, значит.

Да, F13, вот.

F13 я сюда положил, и F13 у меня запись.

Все, я это... С другой стороны не мешает же.

Но я что-то забыл совсем.

Пригодилось бы, сегодня я записывал, было неудобно нажимать кнопки.

Ладно, пусть будет... Нет, хотя опасно, вдруг я время записи случайно щелкну и остановлю запись.

Нет, значит, надо... Мы это стираем.

Для этого просто пустую кнопку.

Пока что...

Пока что нечего на нее ставить.

А вот на втором уровне она у меня в сон переводит.

То есть Fn плюс эта кнопка.

Все.

Так, Django Rest Framework.

Django Rest Framework.

Давно не ставил, поэтому сейчас пойдем по туториалу.

Мы устанавливаем Django Rest Framework.

И Markdown и Django Filter сразу же поставим.

Для этого идем в PyCharm.

И ставим.

Кстати, а почему у них это не сделано как, типа, зависимость...

Ой, сейчас на source.

Как зависимость... Как экстра в зависимости.

Давайте проверим.

О, еще 100 пай.

Так, экстра...

Нет, экстра реально не делают.

Очень жаль.

Ладно, ну Django 5.2 поддерживает, значит все хорошо.

Python 3.13 окей.

Мы возвращаемся, ставим Django REST Framework.

UV Add Django REST Framework.

Пробел Markdown.

Пробел Django Filter.

Нам для фильтрации надо будет.

Ставим.

Все, все поставилось.

И мы сразу же коммитим.

Смотрим, что у нас тут поменялось.

Видим, что поставились.

Django Filter, Django REST Framework, Markdown.

И делаем commit.

Так, что у нас тут поменялось?

Админку.

Да, админку давайте мы закоммитим, конечно же.

Админку.

Да, кстати, а я в админке не проверил.

Ну да, вот фильтр, вот поиск.

By title.

Ну ладно.

Короче, create.

Admin.

For movie model.

И теперь install.

все стал джанго фильтр камень так есть поставили дальше что надо нам надо сделать в installed apps идем в settings и тут как раз таки у нас сайт покажешь вот сюда это идет раз фреймворк нам нужно еще

Дебаг Toolbar нам сейчас не нужен, да, не нужен, но мы, может, его подрубим, если надо будет.

Как знаю, можно ли в фастапе скилл лчми админ?

Ну, это если у вас алхимия, да.

Я видел, я не знаю, зачем люди это делают, когда используют не алхимию и не джанго орм.

То есть не джанго проект, например, фастапе проект, и там не алхимия.

Я не понимаю, зачем.

Ладно.

Давайте добавим в urls.py.

Идем в urls.py.

Кстати, мы еще для movies не сделали urls, но сейчас сделаем.

Earl Spy.

Вот сюда мы помимо админки, даже давайте выше админки добавим.

Для этого нам нужно будет сделать include.

Кстати, у нас путь должен будет... Сортировка у нас случится, include станет раньше.

Давайте мы почитаем, что еще.

ResFramework.

Anon permissions.

Да, короче, мы сейчас пока никакие permissions добавлять не хотим.

Да, а остальное дело сейчас пойдем дальше.

Конечно же, мы не будем писать вручную, мы сразу возьмем viewset, потому что зачем, ну, типа, если можно так.

Install jungles framework into the project.

Коммит.

Думаешь ли ты какой-то фронт для своих проектов?

Да.

Делаешь ли?

Извините, делаешь ли?

Короче, иногда приходится.

Вот в рамках программы этой образовательной, которую я делаю сейчас, мы будем пилить фронт.

Но мы будем пилить его максимально быстро.

То есть, опять же, никаких там реактов, пожалуйста, ничего такого.

Нам нужно быстро вывести продукт, а не пилить там все кнопочки вручную.

Точнее, кнопочки мы вручную будем пилить, но

короче, React это трата времени, я не понимаю, зачем его использовать, когда есть, да хотя бы тот же Vue с Nuxt 3, вообще потрясающе, но даже это слишком долго для тех задач, которые базовые, поэтому GNG2 плюс HTMX, все вот так вот очень легко решается.

Ну, и Bootstrap, опять же, то есть просто какой-нибудь готовый набор.

Пилить какие-то свои красивые фронтенды надо только если, ну, можно, если только вам делать нечего или у вас реально задача какой-то супер кастом напилить.

В остальных случаях нафиг надо тратить свое время на не бизнес-фичу.

Главное, чтобы это выполняло задачу, и все.

Так, значит, мы это установили, теперь нам надо наш сериализатор сделать, viewset сделать.

Так, мы делаем serializers, где у нас тут, нет, kickstart, давайте guide.

serializers.py мы идем делаем наших movies serializers.py и мы посмотрим на movie о чем смотреть у нас есть админка вот здесь у нас все поля перечислены

Поэтому мы просто делаем From REST Framework Import Serializers Class Movie Serializer, Model Serializer, Class Meta, Model Movie и Fields.

All никогда не делайте, мы пишем вот эти поля, которые нам нужны.

Так, ID-шник, по-моему, не указываем или указываем?

Как будто бы на чтение нам ID-шник нужен.

Но, по-моему, он сам придет.

Я уже не помню вообще.

ViewSet сейчас мы сделаем.

И подрубим.

А, у нас Space мы, кстати, указывали.

Неймспейс, не указывали отчеток.

Почему-то в том примере нет, а в этом есть.

Пусть будет везде.

Только нам надо добавить перенос.

Почему вот не ставят end, трейлинг, трейлинг спейс, трейлинг кома, извините.

Просто приходится тратить время на то, чтобы вручную это все поставить.

Давайте мы вот так сделаем.

Serializers.py нет.

Вот URLs мы обновим.

Install into the project.

И вот теперь мы делаем Serializer.

Сейчас вспомнить бы.

Модель указали, поля указали.

Как будто бы все, ID-шник даже не нужен.

Давайте мы ID-шник уберем.

Сейчас будем проверять.

Views.

ViewSet нам нужен.

То есть мы идем в Views, создаем модель ViewSet.

Указываем QuerySet, Serializer класс, Permission класс.

Permission класса нам не надо.

Мы пока что Permission никакие использовать не будем.

Поэтому мы идем в Views.

и делаем from REST Framework import ViewSets class MovieViewSet, module ViewSet, querySet MovieObjectsAll, serializer class MovieSerializer, импортируем из serializers.

Все, permission никаких не надо, это указали.

url подключаем к нашему дефолт роутеру дефолт роутер у нас будет в рамках текущего urls поэтому мы создаем новый urls так

boost до сих пор используется мной да мне кажется уже проще писать tailwind не давайте сейчас я мне тут было вот охота пощупать next и view и tailwind я делал так надо на github перейти github на свой github перейти и я делал репозитория публичный на всякий случай example

Как там, next, что-то такое.

Я прям, вот, example, post, next, post, app.

Короче, щупал Tailwind.

Вот так выглядит страничка.

Вот, очень просто.

Очень просто.

Вот кнопочки жмутся, открываем комментарии.

Все, очень просто.

Вот чтобы, вот, например, вот это вот сделать.

Вот я навожу, и вот этот уголочек.

Я потратил час, наверное.

И как вот этот уголочек сделан, как вы думаете?

Инспект.

Сейчас я вам покажу.

Сейчас покажу.

Так, это чтобы он стал... Совершенно долго hidden.

Вот.

Вот это.

Потому что здесь две вещи в одну.

Сейчас я покажу исходник.

это я это я смог сделать то есть я был на грани того чтобы делать без указателя компонент пост нет комментарии это комментарий аватар и вот на него вот вот это да и

Да, full name.

Вот это.

Что здесь происходит?

Абсолютное позиционирование.

Тень, скрытый по умолчанию.

При наведении он отображается.

Фон такой-то, ладно.

Цвет, бла-бла-бла.

Размеры.

Как мне сделать здесь уголочек?

Before.

Говорим before, я добавляю что-то, такой-то размер.

Поворот.

Это квадрат, который повернут на 45 градусов.

С таким-то цветом, тот же самый цвет, что и у этого элемента.

Position absolute.

Z-позиция, чтобы он отображался в нужном месте.

И я нащупывал расстояние, которое будет по центру от этого поп-апа.

Это я вам сейчас объяснял дольше, чем сделать на Bootstrap.

Идем на Get Bootstrap.

И мы идем в Examples.

Ой, Download не надо.

Ты что?

Docs.

Это называется Tooltip.

Tooltip.

Tooltip — это у нас компонент.

Сейчас тут у нас есть Tooltip.

Поиск по странице.

ToolTip.

Вот ToolTip.

Где он у нас?

Он у нас в компонентах.

Странно, что я его не нашел сразу.

Смотрите, как это выглядит.

Бац.

Все.

Это уже кастомный.

Сверху, справа, снизу, слева, сверху еще есть HTML.

Это делается вот так.

DatabaseToggleToolTip.

DatabasePlacementTop.

И...

Вот.

Data, best title, tooltip on top.

Все.

Вот так бы это решилось на Bootstrap.

Так что не, вообще не проще на Tailwind.

Не проще, вообще не проще.

Tailwind это для тех, кто хочет сам стили писать, просто не хочет их писать в CSS-файликах, а готов в классах писать.

Все.

Там не проще, короче, не проще вообще.

Bootstrap прекрасный инструмент.

Вам не нравится Bootstrap?

Есть куча других инструментов.

Если вы на том же Vue пишете, я вот недавно сталкивался, Prime...

view выглядит нормально типа свой стиль да мы идем в каталог компонентов get started next бла-бла-бла давайте компоненты вот пожалуйста что мне нужен тут тип тут есть тип да пожалуйста вот смотрим бац все тоже работает своя стрелочка другого размера но ok вот пожалуйста все легко решается

Ну, тут свой стиль.

Короче, вот.

Не в джинже два шаблона можно бы инъекции скриптов сделать.

Можно было... Смотрите, инъекции скрипта — это что?

Это чтобы у какого-нибудь пользователя отобразился скрипт, который вы вставили, но для этого надо отображать контент, который пользователь вставил.

Например, вы делаете блок-платформу, где пользователи создают посты, и в пост вставляют, что попало, и вы это чистым HTML-ом засовываете.

Конечно же, мы такое не допускаем.

Какой самый простой способ обойти это?

Мы форму для редактирования даем не HTML, а Markdown.

И Markdown сохраняем в базу, а при отображении мы Markdown рендерим в HTML.

И мы в этом Markdown не даем HTML теги сохранять вообще.

То есть если они там появляются...

то они не HTML-тегами, а текстом отображаются.

То есть мы экранируем, и все, вопрос решен.

Самый простой способ.

Посложнее — это дать HTML вставлять, но тогда думать, как там не... Короче, не пускать.

Например, iFrame использовать, чтобы изолировать отображение.

Так что есть разные способы, и делают вряд ли в джинже.

Если вы найдете какую-то статью конкретную, кидайте, я посмотрю, почитаю, интересно.

В Telegram-чате, пожалуйста.

Я, кстати, когда писал на Django, писал на Django Nisi.

Суперудобно, быстро, намного быстрее и комфортнее.

Класс.

Ну, когда-нибудь пощупаем Django Nisi, но у меня пока есть некоторые сомнения насчет этого инструмента.

Не пользовался.

Не пользовался.

То есть я пока не могу сказать, что что-то плохое или хорошее.

Так.

ID надо указывать, он будет только на чтении.

Ага.

Давайте укажем тогда.

Давайте укажем URLs, значит нам нужен From REST Framework Нет Роутер Импорт дефолт роутер Роутер дефолт роутер По-моему в него надо что-то указать Типа имени Да, нет

Нет.

Register.

ViewSet подключаем.

Значит, у нас movies.

R нам не надо.

Movies.

Мы from.views.

Ну, давайте, раз уж мы везде делаем абсолютные импорты.

From movies import views делаем.

роутер зарегистрировали у нас movies movies movie view set а здесь они делают юзер да все единственный и у нас include router urls вот так будет значит у нас здесь будет свой набор urls и

И нам нужно будет app-name указать, потому что мы хотим изолировать app-name movies.

Дальше у нас path.

Path у нас будет без ничего.

Да, как и здесь.

И у нас будет роутер urls.

Path мы импортируем.

И вот этот url-patterns мы подключаем в основной urls уже с префиксом movies.

movies-каталог мы здесь делаем.

нас будет префикс наверное api movies давайте мы на сделаем префикс ps api слэш movies и

Include мы из каталога URLs.

Мы не будем API добавлять, но вот так сделаем.

Окей, давайте запустим, проверим, что у нас будет.

Нам нужно перейти... Так, погенацию мы добавим.

Да, давайте.

По-моему, она и так по умолчанию, но мы укажем.

Settings.

Давайте здесь будет REST Framework.

я укажу здесь так погинать окей settings мы установили тестинг запускаем все стартуем до старт смотрим отлично макси кашин депс значит я что-то упустил смотрим urls

Здесь роутер URLs.

Здесь мой view set.

Здесь URLs это... Да, я ему искал movies.urls, конечно же.

Мы сами себя импортировали этот же файлик.

Перезапускаем.

Too many values to unpack.

Роутер URLs.

Include, потому что надо сделать include.

Роутер urls.

Смотрим, перезапускаем.

Include у нас джанговский, импортировался джанговский.

Все, стартанули.

Проверяем и потом коммитим.

Переходим в браузер.

Вот у нас есть api movies.

Перейдем сюда.

Slash api, slash movies.

Бац, api root.

Все, есть.

А, movies, movies.

Все, я был неправ.

Значит, нам нужен... Это же api router.

Мы здесь movies добавили уже.

Я был неправ.

Нам надо сделать что?

Мы подключаем...

Какой-то API URLs у нас должен быть.

Какой есть хороший тон?

Я, может, что-то пропускаю, я забыл, я не знал.

Moves URLs.

Какой-то общий роутер.

Да, наверное, знаете, что мы сделаем?

Мы сделаем вот так.

Там же есть nesting роутеров.

Сейчас.

Routers.

API Guide.

Render.

Вот.

Routers.

Вот.

Можем делать вложенные роутеры.

Вот.

Using conclude with routers.

URL patterns.

View.

Роутер нет.

Вот.

Router URLs.

Include.

Extractions не то.

Я хочу роутер в роутер вложить.

Кастом роутер нет.

Эксампл нет.

nested-router-slot, а, это отдельно, ну ладно, тогда, когда здесь просто api, ладно, если, да, короче, пока так, обновляем страничку, вот, все, мы в movie list, вот api-root, это будет просто api, на api переходим сюда, роутер подключен, вот, get api сделали, вот,

Переходим в Movies.

Смотрим.

Movies у нас пока что пусто, но мы можем создать.

Мы можем сделать пост.

Давайте создадим фильм, и мы не будем ничего выдумывать.

Мы возьмем то, что мы уже с вами брали, но оно у нас в отдельной базе.

Для этого надо ее запустить.

Для этого надо эту остановить.

Да, так и сделаем.

Докер композ... А подождите, а мы тут как запускали?

Компози?

Компози.

Значит, мы здесь делаем docker-compose-stop.

Здесь мы делаем... Так, нет.

Мы делаем docker-compose-up.

Стартуем Postgres.

Открываем мой каталог.

Открываем просто все по очереди.

AgeRatings.

так им конечно не надо джен раз ассоциации не надо мой свод все теперь можем стоп на базу у нас все в кэше вот тут пока полежит и мы будем брать вот отсюда названием почему обязательно сортировать через базу сетей так все вытащила ладно окей берем название вставляем description берем описание вставляем релиз да это у нас есть

12 января 1996 года.

12 января.

Быстрее набрать самому.

12.01.1996.

Классный интерфейс для нас предоставляет, кстати, Django Duration.

Duration у нас есть тоже.

Смотрим.

Operation R. Да, я базу не запустил в новом.

Ничего страшного, мы запускаем заново Dogger Compose App.

Минус D. Postgre запускается.

Мы можем просто опубликовать форму заново.

Он скажет, что точно хочешь опубликовать форму заново?

Я скажу, да, я точно хочу опубликовать форму заново.

Все, успех.

Мы завели, у нас 201 created.

Статус, опять же, все в комплекте DRF, это все делает.

И... Да, тут есть описание, все окей.

Теперь мы можем перейти на список.

MovieList.

У нас в списке один элемент, вот у нас id есть.

И мы делаем что?

Мы можем перейти по id.slash1.

И получить детали.

Мы можем обновить.

Например, я хочу обновить duration.

Вот, пожалуйста, put.

Обновил duration.

Ну, я могу заново сказать duration 89 минут.

И я обновлю его.

То есть у нас полный крут работает.

Ну, delay сейчас тестить не будем.

Да, можем JSON-чик напрямую посмотреть.

Но тут все окей.

Все.

Есть.

Movie есть.

Смотрите, как мы с вами быстро справились.

Так.

Вопрос в комментарии.

Есть ли что вам добавить?

Мы сейчас остальные модельки сделаем.

И интересный момент, кстати, это релэйшншипы.

Это чуть сложненький момент, потому что оптимального решения как будто бы нет.

Вот релэйшнс.

ДРФ сам не делает Select Related, Prefetch Related, поэтому было бы слишком много магии.

Поэтому нам надо вручную это.

Но мы это сделаем.

Slug Related Field.

Это по Title.

А у нас по слагу, кстати, будет.

У нас сейчас Age Rating.

Он по слагу у нас будет связан.

Это сериализатор.

Ммм.

Переференс, ну это если мы... Да, вот тут, кстати, вот минус.

Короче, тут у нас нет способа загрузить по желанию клиента с связями или без связей.

В том, в этом... В FastUp и JSONUp мы предоставляем возможность загрузить со связями, но позволяем загружать без связей.

А здесь мы объявляем сериализатор,

Я не помню, тут можно ли выбирать поля, то есть сказать, что мне это не надо сейчас подгружать.

Если есть, то хорошо, если нет, то тут получается так нельзя.

Hyperlinked fields у нас еще есть.

Короче, сейчас посмотрим.

Давайте мы сделаем жанр, наверное, нет, это many-to-many, да, делаем тогда age-restriction, age-rating, age-restriction, другое age-rating.

Вот у нас age-rating, мы сейчас заведем модельку age-rating.

Мы с вами делали вот эту модельку без айдишника.

AgeRating.

Вот так выглядит AgeRating.

У нее поле Name, Primary Key, поле Description и связь с Movies.

Значит, я делаю поле Name и Description.

Мы сейчас делаем это в PyCharm.

Да, закоммитим.

Что у нас есть?

Закоммитим, потому что у нас все хорошо.

Значит, пойдем по порядку коммитить.

Снимаем все и читаем внимательно.

Так, сериализатор мы могли сделать без всего.

Поэтому сериализатор без остального.

Поэтому пишем createMovieSerializer.

CreateMovieSerializer.

Дальше.

Views.

Мы могли сделать это.

Да, у нас уже есть сериализатор.

CreateMovieViewSet.

Дальше мы делаем...

create router for movies api and urls create urls наверное and router else and router и еще еще мы делаем register register router api api router api router

И нам еще нужно settings, да, set pagination for rest framework.

Потрясно.

Что мы делаем дальше?

Делаем AgeRestriction.

Моделька.

AgeRestriction.

AgeRating.

AgeRating.

AgeRating.

Мы делаем класс.

AgeRating.

Models.

Models.

Мы берем из DjangoDB.

Models.

У нас будет name, то есть название.

Так мы его называли.

Сейчас посмотрим.

Я в Readme делал.

У нас будет возрастной рейтинг, да, name и description.

Значит, у нас будет name, char field, max length.

Там 10 символов хватит, там вообще 2 символа, 4 символа максимум, по-моему, pg-17, да, или как там.

Короче, да, 10 хватит точно.

Description.

А, да, и primary key, потому что это у нас primary key.

И description.

Description это у нас будет text field, потому что null false, а вот blank true.

То есть, ну, вдруг там ничего не заполнено, ничего страшного.

Привет, что думаете, фастапи или джанго для больших проектов?

Фу-фу-фу.

Ммм.

Не знаю, я буду на этот вопрос отвечать в рамках программы образовательной, которую делаю, потому что мне нравится скорость разработки на Django, это действительно быстрее, вот вы можете сравнить, что мы с вами сейчас делаем, сильно больше, чем мы успели за первый стрим по фастапе JSONAPI, но как только возникают, например, вопросы о SYNC, я вот с Django в SYNC еще не работал, а это иногда нужно, подождать несколько сервисов сразу, например, такое бывает.

В Django есть async сейчас уже много где.

Я не щупал, у нас будет эфир буквально следующий, кстати, через неделю.

Посмотрим на async.

И я бы все-таки для большого проекта брал скорее Django, потому что очень много из коробки есть.

На фастапе еще не так много из коробки.

Но с алхимией мне нравится работать больше, чем с Django.org.

Но Django.org прикольная тем, что она довольно простая.

Ну, для простых запросов.

Для сложных она более сложная, чем алхимия, как мне кажется.

Короче, слушайте, тут на вкус и цвет.

Если вы работаете в компании, не сами для себя пилите, а работаете в компании, вот что там есть и нормально.

Как бы, блин, я бы не сказал, что что-то прям сильно лучше другого.

Сложный вопрос, сложный вопрос, потому что я люблю писать на фастапе, но я понимаю, что на фастапе мы очень много лишней работы делаем, и мне чисто со стороны там бизнеса кажется, что на джанго быстрее делать.

Но иногда я вижу такое просто на джанго, что делают, что лучше бы это был в фастапе.

Потому что вместо того, чтобы делать нормально на джанго, на джанго с фреймворд,

пили свои костыли, велосипеды хуже, чем Jungle Race Framework, хуже, чем Jungle Ninja, я уверен, хуже, чем то, что есть, и получается, что фигня какая-то выходит, ну и нафиг надо.

Еще крудов не было.

Так у нас есть уже круды, вот они все, вот здесь.

Мы сами не писали, да.

Сейчас, где у нас тут...

В этом весь кайф.

Вот у нас в Model Viewset все CRUD.

Вот у нас Create Model.

Вот у нас часть CRUD Create.

Дальше у нас Read R. Вот Retrieve.

Получить объект или лист.

Вот у нас получить список.

Все это уже готово.

Это писать заново?

Ну смысла нет.

Оно уже есть.

Это немного строчек, но зачем их писать, если они уже есть.

Можно немного разъяснить по поводу null и blank параметров.

Они несут один смысл.

Нет.

Null — это значит, что в базе данных поля может быть null.

Blank — это значит, что может быть пустая строчка.

Это важно для формы, которую будем в админке заполнять.

Сейчас покажу.

Если null... Короче, если blank указать true, то мы можем пустую строчку отправить, то есть не заполнять поле, и в базе оно сохранится как пустая строчка, не как null.

Так.

Праймерики указали.

Давайте проверять, как это будет работать.

Мы делаем managePyMakeMigrations.

Так.

Смотрим, что он нам скажет на этот счет.

А, то, что мы здесь поменяли.

Да, давайте мы это сделаем.

И закоммитим.

Ну, короче, тут надо применять все миграции.

Потому что мы поменяли здесь на tuple.

Я скажу, что мы поменяли здесь на tuple.

Здесь migration.

Короче, когда мы в рамках модели в Django меняем что-либо, вообще что-либо, надо обязательно сделать миграцию.

Так.

Migration.

for ordering value on movie и теперь нам надо age rating добавить в init from movies .

models .

age rating import age rating as age rating кстати вот здесь сортировка должна сама случиться мы включали это isort и мы делаем в терминале make migrations create model

AgeRating.

Смотрим.

Name.

Так, вот null по умолчанию и так, поэтому мы не указываем.

Null false в Django по умолчанию.

PrimaryCase.

Realize false.

Так, а напомните, в чем разница с lag-field?

Он только сам генерит это или что?

Нам слаг здесь не подходит же.

сейчас models .

чарфилд models .

слаг фил слаг он ссылается на другой дам нам оксан тебе index.ru голове не код нет в чем проблема

То есть он наследник CharField.

Отличие, что у него Validate Slack.

А, что здесь... Да-да-да, все, что у нас по значению.

Но нет, мы это не будем делать.

Да, все, нам не нужен Slack.

Так, делаем миграцию, применяем, смотрим, что все будет окей.

Идем...

MyGrade, все применилось, все уговорим, сохраняем.

Потом, если что, откатим.

Create, AgeRating, Create, AgeRatingModel.

Подождите, мы откатываем уже сейчас.

ManagePy, MyGrade, минус 1 тут можно так?

Нет.

MyGradeMovies, минус 1 можно так?

Нет.

Значит, 0, 0, 0, 1 вот так.

Нет, я дропнул.

Ой, migrate.

Ну ладно, уже пофиг, дропнул, дропнул.

Мы же, конечно же, конечно же, должны указать класс мета, еще и string, класс мета, ordering, name, dev string, string return self name.

Вот так вот, теперь красота.

Делаем make migration, смотрим заново миграцию, вот у нас третья миграция, все окей.

Да, вот теперь мы делаем migrate.

Все, применили две иммиграции, все окей.

И сохраняем.

Ну, помогает при создании иммиграции, если ты добавил новое поле в уже созданную модель.

Да, а то можно просто добавить иммиграция проекта успешно, а blank позволяет оставлять поле пустым в админке или форме.

Да, абсолютно точно.

Все так.

Так, покажите мне.

Миграция все окей.

И нит все окей.

Сейчас будет у нас ошибка коммита, потому что не было ассортировку.

Как будто вот это должно быть выше.

А мы игнорили весь файл или мы игнорили...

Только одно правило мы игнорили.

Ну-ка, если я это выключу.

Сделаем roof.check.

А почему у нас не применяется?

Смотрите, сколько у нас правил не срабатывает.

А мы pre-commit устанавливали вообще?

pre-commit run, минус-минус all files.

Здесь уберем, да, мы не устанавливали, похоже, pre-commit.

И давайте сразу же сделаем с unsafe fixes.

Руфчек, минус-минус фикс, минус-минус он сейф фиксос.

Вот, говорит, пять нашел, три осталось.

Ну, что тебе не нравится здесь?

Line too long.

Ну и пошел вон, я тут ничего не сделаю.

Ну, типа, что мне, разбивать здесь эту строчку, чтобы вот эти там, сколько, три символа сэкономить?

Пошел вон, нет.

Нет, просто нет.

Пофигу.

Пофигу.

Пофигу.

Пофигу.

Короче, settings тоже исключаю, потому что, ну, мне неохота.

Вот, мне неохота.

Короче, мы делаем так.

Мы из каталог.

Settings.

.py.

Я исключаю правило, потому что я не хочу ими заниматься просто.

Да, это важное правило, но сейчас я этим заниматься не хочу.

Я могу заигнорить строчку там на месте, либо я могу заигнорить сейчас это здесь.

Я заигнорирую сейчас здесь, потому что пошел вон.

Потому что не хочу плясать под его дудку здесь.

Дальше.

Вот это игнорим.

Потому что с getenv вообще мы потом отдельно разберемся.

так и вот это мы игнорим потому что ну в конфиге то у нас может быть много где длинных строчек это нормально все так проверяем заново проверяем заново не понял мой скаталог слышь так давайте так и

Вот все.

Просто он, видимо, от вот этого мы из каталога пляшет.

Хотя мы source указали, но ладно.

Окей, все.

Значит, вот смотрите, сколько у нас фиксов-то не прилетело.

Вот сортировка случилась.

Лишний импорт убрали.

Сортировка случилась.

Сортировка случилась.

Добавили здесь...

ManagePy не надо трогать.

Иначе как надо.

ManagePy исключаем тоже.

Rollback просто его не трогаем.

Вот так и все.

Потом его в Ignore тоже надо будет докинуть.

Ладно.

Run, pre-commit and install.

Все, есть.

Так.

Моделька у нас есть.

Добавим ее в админку.

Идем в админку.

Админка, админка, админ.

Делаем все то же самое.

Только у нас теперь еще будет ageRating.

Admin.

Register.

AgeRating.

Класс ageRating.

Admin.

Все то же самое.

ListDisplay.

Name.

description дальше есть дисплей links да пусть только ним и будет дальше лист фильтр не хочу нам еще до search fields name и description чечен указан ничего не надо больше все все нормально сохраняем ой сохраним смотрим сурин это я да всем привет и

Заходим в админку.

Переходим сюда.

Slash admin.

Edge ratings.

Так, ничего нет, но мы сейчас создадим.

Мы сейчас будем создавать это тоже через API, потому что можем.

Ты знаешь, что делаешь самые путевые видосы?

Нет, не знаю, как это узнать.

Собирают они не так много.

То есть у меня вчерашний, как вчерашний, недельный, ну, предыдущий, короче, ролик, который я выпускал неделю назад, он собрал типа что-то там тысячу или сколько, давайте посмотрим.

Так, вот смотрите, мы переходим на... Пропало куда-то.

YouTube.com.slash.

Собачка.

Вот, Сурен Хоринян.

Enter.

Почему-то предлагать перестал, очень странно.

Видео.

Вот.

Даже 2000 не собрал.

Даже 2000 не собрал.

На канале 13 тысяч подписчиков.

То есть из-за того, что я выпускаю, скорее всего, мое предположение, из-за того, что я выпускаю очень разные видео, хоть и я считаю, что в одну тему, то есть вот про там питон, про аннотации, их посмотрели одни люди, да, вот где-то даже 3-4.

Что-то про Telegram-бот.

Кто-то подписался по Telegram-ботам, и ему джанго там в фастапе неинтересно, не смотрит.

А кто-то, наоборот, по фастапе подписался.

И поэтому сами все ролики собирают немного.

Ничего с этим не могу сделать.

Я считаю, что смотреть надо все ролики, потому что я в каждом рассказываю что-то новое.

И оно в названии не заявлено.

Но я показываю какой-нибудь трюк классный.

По крайней мере, я так считаю.

И поэтому как бы вишни посмотреть не будет.

Ну...

Прям даже комментарии есть.

Типа, я эту тему знаю, но я посмотрел и нового для себя узнал.

Ну, прекрасно.

Не зря смотрел.

Вообще супер.

Спасибо.

Так, короче, идем дальше.

Я к этому веду.

Не обращаю внимания на количество.

Важно качество.

Да.

Документацию навесить.

Документацию навесить.

А надо?

Надо ли?

Так, что мы делаем?

Мы коммитим.

Админка, короче, есть.

Коммитим, что мы админку сделали.

Create.

Вот здесь у нас, кстати, должно тоже... Нет, подождите, а что ему не нравится?

Почему он считает, что... Смотрите, админ используется, а он почему-то по чарам подсвечивает, что будто бы не используется.

CreateAdminForAgeRating.

Сейчас у нас из-за сортировки один раз коммит оборвется.

Вот, оборвался, сортировка случилась.

Все, говорим коммит.

Все окей.

Так, и мы делаем сюда точно так же сериалайзер.

Да, сериалайзер с... По-хорошему, как модулс, надо отдельно сделать.

Да.

Будем ли мы это делать сейчас?

Нет, не будем.

Сейчас сюда все запихнем.

Блин, я даже не знаю.

Тут я борюсь с самим собой.

С одной стороны, я считаю, что нужно выделить отдельно.

С другой стороны, мне неохота, потому что у нас точно будет... Блин, ну ладно, давайте сделаем.

Назовем это Serializers.

Movies.

Новый Python Package.

Назовем Serializers.

Создали Serializers.

Теперь вот это мы сюда перенесем и назовем его...

вот рефактор rename movie и теперь у нас вот здесь есть нет views

Вот, здесь не поменялось, очень странно, но и правильно, потому что мы вот здесь init сделаем.

From movies.serializers.movie.

Movie serializer мы импортируем s. Movie serializer тут тоже самое надо будет сделать.

И... Постапи better.

Хорошо.

Зачем лучше?

Начальная стройка постапи занимает массу времени.

Да, да, я согласен, поэтому я...

Если я стартую новый проект на фастапе, я беру свой же каркас, который я вот в фастапе BaseApp выложил, и я его использую.

Так, значит, мы делаем... Во-первых...

serializers package что тебе не нравится то же самое мы сейчас идем вот сюда и doesn't rename потому что мы не просто так это делаем ну алё serializers сохраняем и делаем коммит

Где у нас commit?

Вот мы делаем commit.

Говорим вот так сразу с package.

Все окей.

И теперь мы идем сюда, создаем age-rating.

И мы делаем... Что мы делаем?

Мы делаем сервизатор для AgeRating.

Тут еще проще будет.

Я все равно скопирую, потом мы что-нибудь сломаем, потому что копипаста.

Я такой скажу, а, точно, это же копипаста.

AgeRating.

Да?

Да.

AgeRating, бла-бла-бла.

Что у нас тут есть?

Name, только.

Description.

Все, готово.

Мы его в init докидываем.

Точно так же только у нас будет ageRating.

Сортировка сейчас сама случится.

Мы говорим ageRatingSerializer.

create ageRatingSerializer.

И еще раз, потому что у нас сортировка случилась, можем сравнить.

Да, вот он наверх поднялся.

Идем в Views и делаем, ну эти я уж не буду разносить, мы делаем AgeRatingSerializer, класс AgeRatingViewSet, QuerySetAgeRatingObjectsAll, Serializer класс, все, готово.

Мы его подключаем к роутеру.

urls роутер мы делаем prefix age ratings views age ratings view set app name movies да и теперь мы проверим что это у нас вообще работает идем в давайте сейчас мы все что левее закроем давайте все закроем короче other tabs close our tabs переходим сюда слэш ай пи ай

Видим, что у нас есть Movies, Age Ratings.

Вот я перехожу на Age Ratings.

Что у нас здесь?

У нас здесь пусто.

Но мы можем создать.

Вот мы сейчас будем создавать.

Мы будем создавать.

Проверим.

Кстати, я хочу через минус, например, сделать.

Давайте сделаем через минус.

Нам никто не мешает сделать через минус.

Обновим страничку.

age-ratings и идем создавать идем в патчарму здесь у нас есть age-ratings мы создаем g да general audience типа общее вообще g и вот у нас описание такое-то вот

Красота.

Пост.

Бац.

Сделали все.

У нас все есть.

РН, РН.

Это я не хотел.

Мы сейчас делаем патч.

Просто перейдем на него.

Слэш.

Слэш G, кстати.

Вот.

Да.

Да.

Он сразу же все нормально это прочитал.

Мы делаем патч.

Мы сюда вставим с... Вот давайте откроем Ридми.

Патч.

Вот у нас lf, только, короче, слэш n. То есть у нас здесь не будет rn.

Да, проверим.

Ставим сюда.

Бац, ничего подобного.

Ладно, окей, как сохранил, так сохранил.

Пофигу на это, сейчас не будем запариваться.

Есть.

Кстати, чего еще нет в Django REST Framework?

Мы не сможем сделать атомарную операцию с... Я вот показывал это на предыдущем эфире.

Там мы создавали новую запись.

Мы создавали новую запись, и в той же транзакции, в том же HTTP-запросе, мы к этой созданной сущности привязывали другую сущность.

То есть мы могли создать запись и обновить другую, добавив ей relationship, или создать одну, создать другую и их связать.

В Jungle's Framework, я не знаю, есть ли такое встроенное, мне кажется, нет.

Я не встречал.

Это атомарные операции, там я показывал.

Значит, окей, теперь я хочу начать их связывать.

Мы потом новые записи добавим.

Это правда, каждый ролик узнаешь совершенно неожиданную штуку.

Вот, класс.

Я это на самом деле... Ну, не то, что я это делаю прям сильно нарочно, я просто делюсь тем, что считаю важным.

Но я на это обращал внимание вначале.

Я специально думал, что вот надо будет показать чуть больше, чем заявлено, потому что когда я учился программировать, то я смотрел ролики тоже всякие разные...

мне было в кайф что я из ролика который я включаю который я думал что уже знаю узнаю новые то есть я включал какую-то тему и мне нужно было найти какое-то решение я понимал что вроде это знаю но вот что то еще не знаю я помимо того зачем пришел уносил с собой еще новые знания и мне это так приятно было типа вот я не зря посмотрел ролик и вот я хочу чтобы было приятно не зря посмотреть мой ролик так комитет что мы сделали и

и начинаем строить связи.

Если в Atomic что-то там не сработает, так это надо писать.

Прикол в том, что на фастапе JSONAPI

Это писать не надо.

Вот мешочек квест бы нам допилить еще, но я не знаю, сегодня, наверное, вряд ли.

Вот смотрите, atomic operations.

Вам не нужно писать код для этого дополнительно.

То есть вот исходя из того, что мы сделали, но вот здесь мы сейчас делали view set.

Это по аналогии, да, больше букв, но все же по аналогии это view.

Но view у нас один делается на всех.

Смотрите.

Смотрите.

Это то, что мы делали на фастапе.

Это мы же сравниваем, да?

Мы делали на фастапе.

Вот у нас generic view, вот.

Мы сделали больше кода само по себе, да.

Но смотрите, здесь мы указали, что нам нужно будет подтягивать сессию алхимичную, асинхронную, что мы ее вытаскивать будем и прокидывать вот это кварги для...

слоя, data layer.

И все.

И дальше мы этот generic view используем везде.

То есть мы этот generic view прокидываем всем остальным.

В junkress framework нам надо создавать каждый раз заново view, и я считаю, что здесь чище, здесь чище, но вот на фастапе вот это удобнее, считаю.

Нам два раза сделать одно и то же не надо.

Зачем?

Ну, здесь модель надо связать просто, но у нас же и так в сериалайзере оно связано.

Я не знаю, может, можно query set не указывать, и он из сериалайзера возьмет модельку, но я сомневаюсь.

Что у нас тут?

Да, видите, должно быть.

Хотя нет, он же может ее...

get query set, ну да, если query set none, да, если query set none, он нам скажет, что надо либо get query set переопределить, либо, вот, короче, нельзя, вот, но, смотрите, мы вот в фастапе объявляем модель, вот, например, age rating, объявляем схему, age rating, объявили, да, тут нам надо несколько раз объявить для разных там правил схемы, окей,

Но затем генерируется не только, вот что мы сейчас с вами увидели, ну вот CRUD, да, но еще генерируется Atomic Операции.

И мы можем делать Add, создать новый объект, Update, обновить существующий объект, удалить существующий объект.

И вот пример.

All operations remove objects.

Нет.

Local identifier.

Вот, классный пример с local identifier.

То есть я говорю о томик операции.

Один запрос, один постзапрос.

Operation add.

Я говорю, какой-то локальный ID.

User.

Создаю юзера.

И дальше говорю в этой же операции, в этой же, создать юзер био с такими-то свойствами.

Там в Москве родился любимый фильм «Такие».

Смотрите, сразу же выстраиваем user, то есть тип, вот у нас тут указан, type user, вот он, type user, и вот у нас user.

Дальше data, это данные для связи.

LID, это local ID, вот у нас local ID.

Type user, ну это надо снова, почему так, да, этот вот этот user, не потому что здесь type, извините, кого запутал, это потому что на user bio, на схеме user bio, свойство user это relationship алхимичный на user, а вот здесь type, вот это уже type.

И все, у нас после создания автоматически уже вот у нас user создан и user bio связан с этим юзером.

Это очень важно, это очень удобно.

И main-to-main тоже тут работает.

То есть, например, parent создаем, child создаем.

Создаем ассоциацию parent-to-child.

Все, после создания у нас есть parent, child и ассоциация.

Пожалуйста.

Короче, по-моему, это очень классная штука.

И вот сейчас мы не можем так сделать в одной операции, создать новый дженнер и обновить существующий movie и добавить ему этот жанр.

Ой, не жанр.

Ну, жанр, это мы пример с жанрами делали на том занятии, на том эфире, а здесь это будет age rating, допустим.

Если что-то вообще новое, то твой ролик растягивается на пару дней, пока руками все переписать, что-то изменить, потестить, док посчитать, прям как мини-курс.

Да, я поэтому стал ролики покороче делать, потому что вот эти ролики там по часу-полтора, они и сложные в производстве, потому что пересматривать потом после монтажа, причем не один раз.

Также это сложно в просмотре.

Я не знаю, может быть... Смотрите, я вижу две крайности.

Кому-то в кайф большой ролик, потому что из него сразу много чего узнаешь.

Кому-то не в кайф большой ролик, потому что он ищет конкретную задачу, например, «Money to Money».

И у меня в ролике, например, про связи все.

И main-to-main, и с ассоциативным объектом, и без него.

Я считаю, что это много полезной инфы, но она не всем нужна, не все готовы такой длинный ролик смотреть.

Поэтому, ну и плюсы и минусы есть.

Так вот, атомик операции нет, значит, что мы делаем?

Мы с вами делаем релэшншип сейчас.

Да, давайте закоммитим, что мы сделали.

Делаем релэшншип в сериалайзере и пытаемся создать со связью просто обновление делаем.

AgeRatingViewSet, значит, мы делаем...

Create AgeRatingViewSet.

Сортировочки случились.

Все окей.

И... Идем связь строить.

У нас сериалайзер.

Нет, смотрите.

В Movie нам надо сделать связь с AgeRating.

AgeRating.

И... Ну ладно, давайте так.

Models.

ForeignKey.

Значит, name, да, name же, age, rating, onDelete.

Давайте мы заблокируем, то есть protect, то есть чтобы нельзя было удалить, если у нас, типа, фильмы есть.

А, вот, to, не name.

Name вообще непонятно откуда взялся.

onDelete.relatedName.

movies так и будет не трогаем этот корень и не трогаем лим час нет прям клинк ту филд нет тебе constraint труда что на базе данных должна проверка быть по моему все обратную сторону даже строить ничего не надо в этом плане джанго сильно удобнее сильно быстрее проще значит нам надо будет сразу же это в админку добавить давайте сначала миграцию

Так, managePy, makeMigrations, смотрим.

Говорит default.

Да, конечно же, я говорю отмена, потому что это будет nullable поле.

У нас может быть фильм пока что без рейтинга, потому что мы еще не знаем его рейтинг.

Например, как сейчас.

Вот, идем смотрим миграцию.

Добавили связь, все окей, есть рейтинг.

Так табличка называется, хорошо.

Добавляем, делаем commit.

Да, применяем миграцию, проверяем, что мы мигрировать-то тоже можем, migrate.

Все окей.

Окей.

Movie.

Окей.

Add.

AgeRating.

AgeRating.

RelationToMovie.

И теперь мы идем в Serialize.

Нет, сначала в админку давайте.

В админке посмотрим, как это выглядит.

Я хочу...

Здесь указать, что у нас будет еще и AgeRating.

И более того, я хочу это еще и в фильтр засунуть.

Сохраняем.

В любом случае, перезапустим.

Идем в админку.

Так, у нас есть фильм.

Ой, рейтинг тут.

У нас есть фильм.

И у фильма есть AgeRating.

Давайте мы свернем панельку, чтобы было удобнее.

Мы можем фильтровать вот по рейтингу.

То есть, фильмы только с рейтингом G или без рейтинга.

Вот без рейтинга.

Я теперь перехожу к этому фильму.

И хочу сказать, что AgeRating у нас... Ну, тут не G. Мы создадим новый...

Мы создаем новый рейтинг.

У него R, по-моему, да.

Мы сейчас посмотрим.

Вот здесь у нас все было.

Movie.

R, да.

Мы R рейтинг сейчас создадим в базе.

Edge rating.

Вот R. Надо все остальные тоже сделать, но сейчас это не так важно.

Мы идем в браузер, указываем R. И указываем вот здесь все, что нам надо.

То есть мы уже эти описания писали, сейчас они будут заново выдумывать.

Save.

R мы создали уже в базе.

Все, сохраняем.

Теперь у нас есть relationship.

Мы можем отфильтровать по R. И видим, вот фильм с рейтингом R. Можем все сказать.

Давай мне все.

Вот.

И у нас есть фильм с рейтингом R. И мы можем перейти в age ratings и увидеть, что у нас есть еще и рейтинг R. Все окей.

Давайте, знаете что?

Я люблю классную штуку делать.

Сейчас покажу.

Пум.

Текст в wrap возьмем.

Так, commit.

Add age-rating to admin.

Add movie age-rating to admin.

И мы сделаем вот что.

Я хочу movie-admin.

Нет, вот здесь сделать dev-short-description.

обж.

Это у нас рейтинг сюда приходит.

И мы сделаем текст в wrap в wrap description width давайте 50.

Да.

Вернем нолик.

Вот так.

Это как вариант.

И вместо description у нас будет short description.

Так.

Это не search fields, это вот здесь list display.

Обновляем страничку.

Бац, вот.

Единственный минус все равно, я хочу увидеть это допустим до первого переноса.

То есть если у нас есть перенос,

то до первого переноса.

Поэтому...

description description if перенос in да давайте двойной перенос in description то description это будет вот самый первый по двойному переносу и тогда мы вот этот закидываем тогда у нас если там слишком длинная первая строчка она обрежется если она так то мы ее и возьмем все давайте смотреть обновляем и не обновляется интересно смотрите я обновляю страничку у меня страничка крутится выше то есть я просто рефреш делаю

Почему так?

Давайте посмотрим.

print description в виде raw string.

В смысле, representative.

Ага, потому что rn.

Бесит меня, что этот rn почему-то не... Это, видимо, из-за формы, которую мы отправляем.

Но окей, мы сделаем replace rn.

на все обратный слэш n просто вот и все вот теперь сработает обновляем вот все вот описание то есть наш short description заходим сюда и здесь полное описание красота красота вот вот давайте сделаем short description short description

For Age Rating.

Готово.

Так, Relation Ship мы построили, но в сериалайзер еще не засунули.

Идем в сериалайзер, идем в Movie и говорим, что здесь еще Age Rating будет.

Давайте посмотрим, как он нам это выведет.

Age Rating.

Сохраняем.

Обновляем MovieList.

EdgeRatingR.

Он нам вывел строчку.

Он вывел строковое значение.

Давайте мы можем через Django Debug Toolbar отследить.

Давайте мы напишем AddEdgeRatingR.

Потому что здесь по-хорошему-то age-rating id надо вытаскивать, age-rating вытаскивать не надо.

А знаете, как можем проверить это?

Очень просто.

Мы укажем вот здесь на age-rating не self-name, а вот так, например.

Сейчас просто ради примера.

Это быстрее, чем junk debug toolbar ставить.

f строчка.

И здесь будет ageRatingName равно selfNameR.

Вот так.

И смотрим внимательно.

Бац, бац, бац, бац, бац.

Что?

Нет?

Неужели он прям ID сюда подставляет?

Прекрасно, если так.

Потому что я уже не помню, как это правильно работает.

Значит, не тянет.

Значит, не тянет.

Окей, это хорошо.

Тогда погнали.

Вот.

И теперь вопрос возникает.

А как мы тянем...

как мы тянем связанную.

И если мы хотим притянуть связанную, то нам нужно вот этот, где у нас там, Django REST Framework, нам нужно найти API Guide, Serializer Relations, и у нас есть разные варианты.

Значит, foreign key, бла-бла-бла, prefetch related, бла-бла-бла-бла-бла, Serializer Slack Related Field, вот у нас Slack Related Field или нет, Slack Field.

Давайте мы укажем

Но вот мне не нравится, что я не могу сделать выбор, что этот movie view set у нас только либо со всеми edge рейтингами обязательно тянется, либо нет.

Как мне быть?

Если я хочу... Давайте, ну-ка.

DRF optional load relations.

Потому что не всегда это надо.

Optional load relations on serializer.

То есть если... Нет.

Нет.

Нет.

Ну, короче, видимо, нет, я не знаю.

Так, так, сейчас.

LottageRating.

Serialize.

Serialize.

LottageRating.

И... Я просто не хочу тот же самый... А!

Я вспомнил!

Я вспомнил, как мы можем сделать.

Смотрите.

Def.GetSerializerClass.

именно класс и на разные действия можем разное отдавать значит если у нас if self request get давайте так .

get include давайте

pass здесь return that movie serializer вот так мы сделаем git query set предпринять как вариант да это git query set это надо будет кстати тоже переопределить чтобы join сделать вы правы select related для этого join но здесь нам serializer тоже надо обновлять но поэтому мы сделаем так return movie serializer просто include сейчас будет просто include какой-то передан в query set даже не в заголовках даже короче просто в query set movie serializer

Extended, да, назовем Extended.

Вот так.

И здесь мы делаем, вот, видите, у нас бац, и оправдывается, что мы делаем несколько разных модулей.

Класс, MovieSerializerExtended, Serializer, ModelSerializer, Metamovie, Fields, бла-бла-бла.

Но, кстати, мы можем, знаете, что сделать?

Мы можем отсюда унаследоваться.

Мета у нас будет наследоваться от моего сериалайзера мета.

И fields... Ну да.

Fields у нас не меняется, кроме того, что ageRating у нас будет ageRating равно serializers.slugRelatedField.

Да, вот так надо, правильно же?

Так.

Мы указываем slugField.

равно age-rating с этой стороны же, да?

Ой, сейчас.

Slack-related field.

Нет, смотрите, у нас же primary key related field, правильно?

Вот и все.

Many true, read-only true.

Да, не read-only только у нас.

Edge rating.

Короче, мы делаем так.

Primary key related field.

Many не true, read-only не true.

Поэтому это все мы убираем.

Смотрим, что будет.

То есть мы хотим сделать запрос такой же.

Смотрим.

Movie list.

Что-то грохнулось.

Запускаем еще раз.

Is not none.

Не понял.

Я удалил query set и не поставил новый.

Мой серилайзер мета я указал здесь.

Primary key field.

Я не указал вот здесь.

Primary key related field.

Не понял.

А, покажите мне пример.

Вот здесь нет такого, например.

Primary key related field.

Query set.

Мы говорим, что аккаунт.

Кто у нас?

Овнер.

Надо обязательно.

А почему там не надо?

Почему вот здесь не надо, а там надо?

Интересно.

Ну, окей.

Давайте скажем, что у нас query set.

Это age-rating, object-all.

Получается, мы сюда age-rating импортируем.

Ну, ладно.

Не all, а нам надо тогда... Нет, all.

Все правильно.

Предупускаем, смотрим.

Бац, ожило.

Смотрим вот здесь.

Обновляем.

Да, и мы добавляем вот сюда просто include.

И бац.

Нет.

И равно 1.

Ага.

Мы сразу знали define.

Вот, случилось.

Значит, мы его сейчас импортнем.

Только надо сначала в all объявить.

Вот здесь мы делаем s...

Перенос должен случиться.

Да, есть.

Идем в views.

И здесь мы просто импортируем еще и вот это вот.

Extended.

Вот.

Обновляем.

Бац.

Бац.

Бац.

А что, где?

А что?

Не понял.

Не понял.

Мы отдаем здесь уже Extended.

Давайте ради интереса.

Fields.

Просто у нас Extended будет наоборот.

Сейчас Limited Fields.

Уберем отсюда Release Date и Duration, чтобы было понятно, что это наш текущий.

Вот, Release Date и Duration ушли.

Primary Key где?

Короче, значит, у нас есть... Вот, я хочу вот так увидеть.

А, здесь у нас только primary key придет.

Но нам не пришел primary key.

А, у нас к одному.

У нас пришел primary key.

Вот, я хочу string.

Это как строчка будет.

Hyperlink нет.

Есть...

Понял, вот этот слаг придет.

Не-не-не, мне нужен... Там есть module-related-field как-то так.

Вот так ссылки, но это неинтересно.

Там как-то есть вложенный... Просто сериализатор, да?

Вот, nested-сериализатор, вот.

Вот это мне надо было, да?

Да, просто сериализатор сюда воткнуть, понятно.

Все, запутался сам.

Конечно же, значит, у нас есть способ указать здесь hyperlinked-module-serializer.

Да, давайте посмотрим, как он нам предлагает его использовать.

Вот, вот.

Вот, вот это нам надо, вот это.

Сейчас покажу.

Значит, у нас будет это hyperlinked.

Сейчас.

ModelSerializer.Serializers.HyperlinkModelSerializer и вот здесь IdentityField вот это будет IdentityField ViewName ViewName у нас

movies, просто age-rating у нас называться будет, а имя мы не задавали, нет, задавали, подождите, urls, вот здесь у нас имя генерируется на основе movies и дальше age-rating с, так, urls, как же он генерирует urls, default router, default router генерирует urls,

Он имя же ставит.

Вот, roads name, base name минус list.

Значит, у нас base name это то, что мы закидываем.

Age, rating.

А, знаете, как мы можем проверить?

Сейчас быстрее будет.

Перейдем туда, куда нельзя.

А, да, сейчас.

Здесь мы забыли, забыли, забыли.

Указать, что нужно было.

Так вот сделаем.

Перезапускаем.

Вот, нам говорят, что такое не знают, API, дальше AgeRating, например, вот, он мне говорит, API AgeRating с имя, вот, AgeRating минус лист, вот, нам сюда надо.

Вот.

Идем.

Сериалайзер.

Вот.

View name movies.

AgeRating-list.

Вот это убираем.

Сохраняем.

Смотрим.

Только нам надо, конечно же, fields.

А мы вот это можем так вообще сделать.

Сохраняем.

Бац.

AgeRatings.

Есть.

Да, это есть.

И movies.

Include равно 1.

Ошибка.

Missing мета.

Потому что мы его удалили совсем.

Мета есть, просто он пустой будет.

Path.

Сохраним, обновим, обновим, обновим, обновим.

Improperly configured at API movies.

Lookup field.

With edge rating list.

You have failed to include that model in your API.

Incorrectly configured lookup field.

Почему?

Потому что надо на ageRating добавить getAbsoluteURL.

Идем к ageRating и говорим def getAbsoluteURL.

И возвращаем return, reverse.

From Django shortcuts import reverse.

Что он мне не предлагает?

Movies age rating list.

Нет, detail.

И у нас не primary key, а у нас name, self, name.

Ну, у нас это и primary key, но, в общем, вот так должно быть.

Хотя я уже не уверен.

Happy movie.

Вот так сделаем.

рейтинг с имя детей вот здесь пока пока пока значит указываем пока муки ну это пока но имя можно хоть так вот так окей проверим еще раз обновляем и пробовали конфигуре толкать field давайте посмотрим где он ругается мы можем прямо здесь посмотреть

Fill to Representation.

Давайте перезапустим, да, на всякий случай.

Дернем еще раз.

Да, ошибка.

Так, to Representation, SuperData, Project Response, Realizer, Data.

А что, пойдем просто вот здесь так вот в дебаге?

Я пока не пойму просто, где им надо пофиксить.

Вот, Representation, Attribute.

Attribute у нас один.

Что один?

Ты чей один?

Это вот свойства фильма.

Так, вот весь фильм.

Вот здесь грохнулось.

Да.

Да, еще раз делаем запрос.

Раз, два, три, четыре.

И вот фильм.

Вот здесь грохается.

Fields.field.field.

Name.

AgeRating.

Вот.

A field to representation.

A field to... Так, а attribute?

Сам к себе?

Не-не-не.

Неправильно что-то.

Сейчас давайте мы просто пойдем.

Я просто уже что-то не соображаю.

Какой-нибудь blackbox.ai python

Я говорю, что меня интересует, please create hyperlinked DRF в серии alizers for these models.

И идем просто эти модельки загидываем, потому что что-то я сейчас туплю, а я не хочу тупить.

Ну, в смысле, не хочу... Короче, давайте... Сейчас, бац, бац.

Эта строчка нам не нужна.

Смотрим, что там скажет.

Ну, я не хочу вложено, я хочу age... Ой.

Я хочу...

Здравствуйте.

Да, добрый вечер.

Пробовал iStar?

Если да, что скажешь о нем?

Не пробовал.

Смотрел доку, пока не пробовал.

Hyperlink model serializer.

Окей, так, давайте.

Сейчас, подождите, ради эксперимента.

Вот это я просто убираю.

И идем еще раз.

Запускаемся вот так.

Improperly configured.

Что improperly configured?

Age rating minus detail.

Couldn't resolve URL for hyperlinked ship.

View name, age rating minus detail.

Где?

Movie, age rating.

У него же movie, yes.

Age rating minus detail.

Нет?

Вот так?

Нет.

Couldn't resolve.

Давайте мы ему это скажем просто.

How to fix.

fix что-то я где-то пропускаю так горизонтальное прокручивание не работает почему чем не тут написал кучу букв

Use Default Router.

Модельки указал.

Так.

Сериализатор.

Сейчас давайте проверим вот просто вот с этим Hyperlink Serializer.

Во-первых, проверим, что у нас без Include работает нормально.

Работает.

Теперь я перейду в API Edge Ratings и мы прям вот эту же

Веб-код, не-не-не.

Я ему подсказываю, что делать, а не он мне подсказывает.

Он, как видите, не справляется.

Приходится своей головой думать опять, опять, как всегда.

Мы вот здесь скажем, что это не ModelSerializer, а Hyperlink ModelSerializer.

Тут у нас ничего не поменяется, потому что у нас в обратную сторону здесь никаких релайшипов нет.

Да, проверим.

Бац, да, ничего не поменялось.

Теперь, допустим, я сделаю то же самое с сервизатором.

movie со стандартным.

Просто здесь мы меняем только на hyperlink модуль serializer.

Обновляем страничку с movies.

Бац, грохается.

Значит, age rating detail, вот, couldn't resolve URL for hyperlink relationship using view name age rating detail.

You may have failed.

Короче, видимо, это где-то внутри onresolved.

И у нас есть один способ плохой, но я его сейчас покажу.

Есть хороший, который мы будем искать.

Значит, я убираю namespace отсюда.

Обновляем.

Бац, работает.

Мне это не нравится.

Почему работает?

Потому что namespace.

Значит, надо дефолт роутеру где-то сказать про namespace, да?

Namespace.

Namespace.

Request resolver match namespace.

Плюс URL name.

Все, это единственное про namespace место.

Default router.

Provide namespace.

Давай app name, вот так.

Это касается include?

Нет.

Баф вот здесь где-то выше.

ViewName.

Где ViewName?

Вот покажите мне.

ViewName.

You also need to ensure that any ViewName parameters on the serializers correctly reflect the namespace.

In the examples above you need to include parameter such as ViewName.

Короче, such as это значит, что мы идем в сериалайзер.

Куда?

Вот куда мне его теперь запихивать?

В AgeRating?

Давай.

Сейчас вот давайте мы здесь вернем, как был, ModelSerializer.

А вот здесь я говорю Hyperlink IdentityField ViewName.

Но я же указываю, вот он, Movies, двоеточие, вот он, ViewName.

Я же указываю AppName, дальше минус, а, Detail, может, вот так?

Вот в этом, наверное, прикол.

Обновляем.

Значит, Movies работает, как работал.

Include равно 1.

Работает, все, отлично.

Единственное, что не может быть слэш один.

Нет такого рейтинга.

Откуда он денечку взял?

Это же не из инклюда.

Не из инклюда.

Почему он так сделал?

Потому что ему нужно подсказать, как часто сейчас JSON API юзает.

Сейчас нечасто.

Каперлинг related field.

Вот lookup field.

Каперлинг related field.

Ну, lookup field.

URL quark у нас остается primary key.

А lookup field у нас...

Не, погодите.

Сейчас блокбокс нам ничего не подсказывал?

Не подсказывал.

Не подсказывал.

Не подсказывал.

Так, name.

Как он здесь name выстраивает?

Name вот у нас, да, должен быть.

Но он же не name строит.

В смысле, короче, вот здесь прикол, что он не то подставляет.

В какой момент он это делает?

Вот он запоминает, что мы сюда передали view name.

Так, реверс нам не нужен.

Глобальный, да, реверс, да.

Use primary key only optimization.

Get object, вот.

Get object, query set, он находит.

Get url, вот.

Казатор, object, primary key или primary key.

Lookup value, get.

Вот сюда он заходит, да?

Вот здесь он строит неправильно.

Да, давайте проверим.

Какой вот ИИ мне подскажет, что я здесь делаю не так?

Вот, где он взял ПК-1?

Вот откуда здесь ПК-1?

Ну, капфилд, ПК.

Объект, age rating, да?

Нет, movie.

Он сам на себя, понял.

Это поле, которое само на себя смотрит.

Все, понятно, почему у нас там два раза одно и то же было.

Это поле, которое на себя смотрит.

Вот это hyperlinked identity field.

Он на себя смотрит.

Movies and Rating Details.

Не туда он смотрит.

Хорошо, если вот так сделаю.

Просто вот так, например.

Просто вот интересно.

Обновляем.

Запускаем еще раз.

Обновляем.

Говорит, а что, куда?

Ему надо подсказать.

мне надо сказать, что это, ну что, hyperlink, хорошо, hyperlink related field, да, не identity, вот так, да, хорошо, query set, да, опять-таки query set своим, ну давай, query set, так, годится?

Стартует, обновляем, бац, все.

Все, разобрались.

Как видите, на фастапе JSONAPI сделать это быстрее.

Ну, потому что я знал, там, наверное, вы бы дольше разбирались.

Но вот это дичь какая-то, вот это дичь.

Очень странно сделано, но ладно.

Вот, наконец, можем сюда перейти и увидеть рейтинг R. Все, как и должно быть.

В обратную сторону, как это отобразить?

Это нужно делать в ложный сериализатор.

Давайте здесь тоже сделаем Extended.

То есть Include равно 1.

Мы сделаем в обратную сторону.

И на этом, в целом, я думаю, мы будем... А, нет, не будем закрепляться.

Man to Man еще посмотрим быстренько.

AgeRating.

Serializer тоже сделаем Extended.

Класс.

AgeRating.

Как у нас там называется?

Serializer.

Extended, да.

То есть конец просто AgeRating.

AgeRating.

А, точно, мы можем же сделать на лист одно, на detail другое.

Да, слушайте, давайте сделаем, но это, блин, фигня какая-то.

Сейчас, давайте сделаем на... Сейчас покажу.

Короче, на detail.

Так, класс.

Сейчас.

Класс.

Класс.

MovieSerializerExtended 2.

MovieDetailSerializerExtended без двоечки.

Это просто ModelSerializer.

И мы здесь сделаем наследник на самом деле вот этого даже.

Мету мы сделаем так же.

AgeRating.

Единственное, что мы сделаем, это AgeRatingSerializer.

То есть здесь у нас будет CrossImport.

Не знаю даже, как это будет чиниться.

AgeRating.

serializer какой-то минимальный нужен получается мы не не выжить serializers serializers .

серия

Нет.

Все правильно, да.

AgeRatingSerializer.

Да, только начатение.

Хотя я хотел бы обновить тоже.

ManyFalls.

Что там еще надо?

Давайте проверим.

Значит, вот это мы будем указывать только если detail и include вот этот.

Значит, идем в views.

Значит, надо сделать get query set.

Да, алло.

Get query set.

Да, почему он?

Get query set.

Вот этот, пожалуйста.

Да, все, услышал.

Значит, if self request... Нет, if self action равно...

Retrieve.

То есть получить один объект.

Мы вернем.

Little details.

Laser extended.

Все, поехал.

Хе-хе, PyCharm.

Что случилось?

Enter не жмется.

Стирание не жмется.

Буквы жмутся.

Что такое?

Ой, блин, PyCharm.

Закрываем, выходим.

Так, terminate.

А подождите, я сейчас открою другой файлик.

Этот закрою.

Открою заново.

Во, протупил.

Extended.

Импортируем.

Только не отсюда.

Делаем serializers.

И, соответственно, это будет detail.

Значит, если retrieve, а если не retrieve, то... Ой, getQueueReset, точнее, это не туда.

Здесь мы делаем тогда... getQueueReset мы делаем...

То есть мы, если на детали, то сразу подгружаем.

И здесь, если у нас include, если self-action равен retrieve, то мы делаем return extended.

Костыли капец.

Мне, конечно, нравится, как больше...

ну, не костыли, но мы это делаем в виде логики.

Мне больше нравится, как в FastApp и JSONAPI мы сделали с тем, что это декларируется, а не логикой делается.

Логика там внутри библиотеки.

Все, значит, Extended.

Что будет Extended?

Мы вложили сериалайзер.

Все, вот и все.

Значит, я хочу перейти на Movie для начала просто.

Оперуд.

Movie.

Вот, я перейду на него.

Просто перейду.

Один.

Работает.

Теперь я хочу, чтобы у меня рейтинг подтянулся полностью.

Мне нужно...

Показать include равно 1.

Вот, вот, вложенный, случился.

Все, прекрасно, это работает.

Значит, это мы коммитим.

В обратную сторону сейчас сделаем и сделаем еще main-to-main.

Это не обязательно, ну ладно, уже оставим.

Окей, окей, create different, create different serializers for movie.

Коммит.

Сортировочки.

Все.

Нет, со второго раза не проходит.

Значит, где-то еще AddReturnTypeAnnotation.

О, ну ты, конечно, придумал.

Так.

Значит, у нас здесь будет базовый сериализатор.

Type.

Вот.

Ну, сериалайзер, да.

А здесь будет QuerySet.

Проверяем заново.

коммит так неуспех self-name говорит нельзя мандал чё мадрид мадрид сквозь месяц бабло magic метод шуткам before get absolute url ничего себе вы придумали ну ладно очень странно я всегда magic методы вообще в самом низ кладу то есть вы хотите сказать что сначала поля потом

Мета-класс, потом Magic методы, а потом мои методы.

То есть сначала мои поля, потом служебное поле, потом другое служебное поле, потом мои методы.

Очень странное правило.

Сейчас последуем ему, но мне не нравится.

Коммитим.

Что не нравится еще?

Скажи мне, скажи мне, скажи мне.

Модуль класс метод.

Magic метод.

Come before get absolute URL.

Так вот он, before.

А, надо, наверное, так?

Нет.

Commit.

Нет.

Roof.

Check.

Давай.

А, у нас есть unsaved fixes.

Ну вот, давай, фиксируй мне.

Просто я не хочу уже это сам чинить.

Missing return type.

Это я поправлю.

Это у нас будет реверс.

У нас строчка возвращает же.

Не знаю.

Похоже на строчку.

Отдаем строчку.

Все, прекрасно, живем.

Коммитим.

Так.

Менеджпай мы не трогаем.

Нет.

Надо его заигнорить.

Я чуть не заигнорил в прошлый раз.

Подумал, что мы его трогать не будем.

Мы не трогали, но мы на все запускали.

Так, окей.

Сериализаторы мы добавили.

Сериализаторы.

Теперь в обратную сторону.

EdgeRating я хочу сделать то же самое.

класс давайте просто рейтинг details и лазер чтобы мы сразу же подтягивали fields то есть у нас класс мета наследник и мы указываем fields плюс movies давайте сохраним так что он не говорит не знаю такие movies еще сейчас узнаешь и

Мы укажем.

И здесь нам нужно будет movie, получается, импортировать.

Movies.

Но у нас это не сработает.

Serializer.

У нас будет movies.

Опять же, как это делать?

По идентике мы это через аннотации решили.

Movie.

Serializer.

Все, у нас циклический импорт.

Мы не true, read only true.

Вот так вот сделаем.

Смотрим.

У нас даже не запустится.

Все, не могу импортировать, потому что у нас циклический импорт.

Как мне правильно вкладывать?

Мне нужен какой-нибудь movie base serializer получается.

movie base serializer сюда переношу команд и для рейтинга то же самое хорошему тогда в обе стороны чтобы рефактор мув переносим что ты мне хочешь сказать еще раз рефактор мув

Мой Base Serializer.

Вот сюда.

Да, что такое?

Еще раз.

Копирую полный путь.

Command, Option, Shift, C. Вставляем.

Нет, не то.

Command, Shift, C. Вставляем.

Вот, полный путь к файлу.

Теперь я говорю Command, Shift, C. Правая клавиша мыши.

Refactor, Move.

Вставляю.

Все, перенесли.

Отлично.

Теперь то же самое с...

AgeRating Base Serializer.

Кстати, Serializer не надо, Base просто делаем.

И здесь мы переименуем F6.

Serializer у нас так, папка сериализаторы.

AgeRating Base.

Сюда перенесем вот этот AgeRating.

Мы делаем правой клавишей мыши, Refactor, Move.

То есть без отношений, без связей друг с другом у нас отдельно вот эти.

И теперь должно стартануть.

Смотрим.

Нет, ничего подобного.

Почему?

Потому что мы AgeRatingSerializer берем из MovieSerializer.

Это так не надо делать.

From MoviesSerializers.AgeRatingBase мы берем AgeRatingSerializer.

Вот так все, заживем.

Бац.

И в обратную сторону.

Нет?

Что тебе не нравится?

Здесь не то, здесь не то, здесь не то.

А мы уже в обратную сторону, да?

Да, потому что мы здесь movie делаем.

То же самое.

From.

Movies, Serializers, Movie Base, Import, Movie Serializer.

Вот, и теперь заживем.

Перезапускаем.

Нет, импорт не могу, говорит.

Где?

Давай Movie Base.

Так вот.

Вот, живем.

Так, окей.

И теперь, как видите, без циклических импортов можно жить и без импорта внутри метода какой-нибудь.

Теперь вот этот detail мы хотим видеть только, только, если вот здесь dev, давайте вот так вот сделаем, getSerializer класс.

Нам нужен еще...

Так, вот здесь isAgeRating, fromMoviesAgeRating, о, serializers, да.

AgeRating, import, AgeRatingDetailSerializer, вот он мне нужен.

As, AgeRatingDetailSerializer.

И идем сюда, мы делаем return, если у нас actionRetrieve, то есть детали, то мы отдадим вот этот сериализатор.

В ином случае AgeRatingSerializer отдадим.

Все, сразу сериалайзер класс убираем, импортируем.

Сохраняем Edge Rating View Set, мы идем подключать, подключили уже, значит мы идем просто детали посмотреть, смотрим, да, нам нужно только Query Set обновить, мы делаем Get Query Set, ровно то же самое, только у нас будет подтягивание ко многим, поэтому это Prefetch Related.

movies movie set да это будет movies я сейчас скажу почему это будет movies потому что мы укажем это на уровне movie уровне movie мы укажем что у нас related field related

name будет movies так они movie set movies здесь мы делаем ретрив movies все да проверяем и у нас запускается успешно смотрим я хочу перейти на какой-нибудь рейтинг и увидеть у него увидеть у него ой

Хочу перейти на какой-то рейтинг и увидеть у него подтянутые фильмы.

То есть вот в списке у нас пара фильмов.

Я хочу увидеть... У нас только один фильм сейчас, но мы сейчас увидим все равно список из одного подтянутого фильма.

Для этого мы переходим на «slash r».

Бац, видим, подтянутый фильм есть.

Все, у нас релайшншип подтягивается прекрасно.

Работает.

Это работает, хоть мне не очень нравится, как это сделано.

Это устарело, как мне кажется, по своему код-стилю.

Ну, окей.

В этом плане все ок.

Подтянули.

Все, значит, коммитим.

Коммитим, коммитим, коммитим.

То есть мы показываем релайшншипы.

Бла-бла-бла, бла-бла-бла.

Бла-бла-бла, бла-бла-бла.

Да.

Ретрив.

relationships ретриеве каждый раз путаюсь ретриеве так сортировочки бац и теперь все равно не прокатило значит я где-то снова что-то профукал смотрим что да да это правильно давайте снова ansi fixes вот и все теперь

Да, managePy не трогаем, managePy заигнорим.

Все, managePy игнорим просто полностью.

managePy мы не трогаем вообще никак, идем поэтому в pyproject.oml и managePy мы просто заигнорим.

Перфайл ignores.

Я не помню, кстати, мы его можем вот так просто managePy на все можем или его надо в отдельный ignore тогда добавлять.

Ну-ка проверим.

Так, звездочка.

Смотрим.

Ну-ка, проверим.

Нет, не знаю.

Значит, нам нужно perfile.ignore.

Extend.ignore нам нужен.

Roof.

Lint.

Extend.

Ignore.

Идем.

Roof.

Settings.

Ignore.

Extend ignore.

Это у нас параметры, да?

Да.

А есть ignore файла.

Ignore.

Правил.

А где ignore файла?

Perfile ignores.

Но это именно правило.

А если я хочу...

Так, roof.ignoreFile.

Extend, Exclude.

Вот, Exclude.

Я его игнорую.

Вот я говорю Extend, Exclude, пожалуйста.

И говорю Extend, Exclude.

Мне нужно убрать.

Полностью не проверять.

ManagePy.

Просто потому что я не хочу сейчас для него отдельно там правила тоже настраивать.

Поэтому делаем вот так.

Переносим.

Лишнее удаляем.

Bad.

Ничего такого.

И проверяем.

Бац.

Он мне говорит, что я не прав.

Потому что

Tool Roof это должно быть.

Оно мне где?

Оно мне здесь.

Tool Roof.

А, это линт.

Просто Tool Roof мне надо.

Понял?

Понял, без проблем.

Это вот здесь вот выше.

Говорю просто вообще полностью, мне его заигнорите, пожалуйста.

Бац, все, прекрасно.

Теперь мы менедж не трогаем.

Давайте об этом заранее отдельно расскажем.

Здесь мы скажем, это не надо.

Exclude, exclude, managepy.

Так, смотрим дальше.

Так, managepy мы эксклюзим, нет?

Rollback.

Так, смотрим, Movie, Serializers, да, это все мы видели, видели, видели, и здесь у нас был Retrieve Relationships.

Все, выбираем, коммитим, успех.

Все, и теперь финально, если есть вопросы, конечно, задавайте, финально смотрим на Main2Main, думаю, тут будет несложно, потому что у Джанги в этом плане довольно легко основное.

Так, значит, гибкости мы с вами фостопично не видим, но ладно.

Main to main.

У нас был жанр.

Давайте мы посмотрим вот тут ритмик.

Вот, фильмы, жанр.

Жанр, ID, Name, Description.

Name, Description мы берем, как и из Age Rating.

Age Rating, то есть у нас Genre.

Но этот Genre у меня будет уже Name.

Так, во-первых, Genre.

Это не надо.

Name есть.

Charfield.

Жанр сотни хватит.

Здесь New Blank.

Окей.

Name.

Окей.

Делаем импорт.

Так, дженре, с, дженре.

Да?

Да.

Делаем джанго...

ой, сейчас, где мы тут, да, python manage py make migrations, смотрим циклический импорт, где он у тебя случился, если у нас до этого все работало, опа, здрасте, да, привет, привет, ты уже к концу подтянулся, ну, окей,

Склический импорт.

Can't import name from partial initialized.

При этом приложение запускается, да?

Нет.

Ага.

Понял, понял.

У нас из-за сортировок поломалось.

Мы делаем просто вот так.

AgeRatingBase.

Вот так.

Бам.

ImportAgeRating.

Еще где-то есть.

Нет, все.

Значит, мы это коммитим.

Вот так вот.

Вот так вот.

Amend.

Зафиксили.

И теперь проверяем вот эту часть.

Бац.

Все.

Все окей.

Alter edge rating on movie.

Как же мы его edge rating-то альтернули?

Мы же добавили там просто имя related.

Ладно.

Давайте мы сделаем так.

Мы дропаем эту миграцию.

Делаем заново.

Вот у нас отдельно alter.

И теперь отдельная миграция на вот эту штуку с genre.

Вот два разных файла.

Я люблю, чтобы было в разных файлах все, что мы делаем.

Значит, у нас есть вот эта миграция, которую мы сейчас закоммитим.

Rename related field on movie.

Это field ageRating.

Нет, он наоборот ageRating.

ageRating.

Да, RelatedNameToMovies.

Вот.

И тут кино.

Кино, прям кино.

Да нет, мы просто это заканчиваем потихонечку.

Уже сейчас мейн-то-мейн вот этот глянем.

И все.

Значит, делаем миграцию.

Migrate.

И говорим, что у нас CreateGenre.

Мы его тоже в админку засовываем.

Идем в админку.

Админ, все то же самое, как AgeRating.

Знаете, как можно сделать ShortDescriptionName?

Можно сделать RegisterAgeRatingGenre.

Genre мы импортируем вот отсюда.

Сохраняем, смотрим.

Бац.

И у нас в админке теперь будет... Здесь обновляем movies.

Вот, generous.

Потому что у них те же самые имена, нафига мне пилить такую же админку, если тут уже есть.

Добавляем жанр.

Жанр, например, бац.

И movies to look.

Следующий строчечку у нас есть.

Дальше криминал.

Вот мы будем добавлять.

Сейчас других у нас нет.

И сохраняем.

Все, есть.

Отлично.

Теперь мы строим связь main-to-main.

Жанры без фильмов нам не интересны.

Точнее так, жанры без фильмов не могут быть, фильмы без жанров могут быть.

Поэтому я считаю, что надо на фильмы поставить жанры, а не на жанры фильмы.

Мы идем в... Да, админка у нас все окей.

create-admin create-genre-admin или давайте так add-genre-to-admin сохраняем сортировочка случилась и все окей main-to-main строим значит movie у нас будет generous main-to-main-field указываем to-genre

Blank true можно.

Related name movies.

Что еще?

Related query name то же самое.

Symmetrical true нет.

DB constraint нет.

DB table сам сделает.

Все, делаем новую миграцию.

Make migrations.

Миграция есть.

Читаем.

Просто main-to-main field.

Я говорю хорошо.

Migrate.

Окей, мы можем пойти в админку теперь.

И в movie, да, мы это не выводили, но мы можем в детали зайти.

И вот здесь в movie мы увидим, вот, generous.

Я могу два, например, выбрать с командом или с control зажатым.

Сохраняю.

И теперь у нас здесь есть связи вот с этими сущностями.

Вот они выделены.

Все окей.

Но я хочу это увидеть в API-ответе.

Для этого мы сделаем что?

А на самом деле у нас-то main уже есть.

Сейчас мы это закоммитим просто.

Мы это закоммитим.

Мы скажем...

create-general-relation, create-movie-vesto-general-relation.

И мы просто... Что?

Что тебе тут не нравится?

Давай еще раз.

Он сортирует нашу миграцию, но мы не хотим, чтобы он миграцию трогал.

Он поменял как будто файлик миграции, да?

Или мне показалось?

Он что-то здесь поменял, да?

Нет?

Ладно.

Запятушки поставил.

Ну окей.

Пу-пу-пу.

Идем в сервизатор.

Значит, нам нужен GenreBase.

Он будет как AgeAtingBase, то есть GenreBase.

У него есть NameDescription.

ID нас не сильно волнует, но можем добавить ID.

И мы называем это Genre.

Дальше.

Мы идем в movie, у нас movie extended.

Вот movie detail serializer extended.

Detail, details, наверное, надо было.

Ну ладно.

И мы говорим, что у нас будет gen res serializer.

Так, не понял, тут что-то свое.

Many to many.

With true, но у нас не с true.

Нет, давайте мы просто так же укажем только many true равно мы импортируем from movies.serializers.genrebase.import.genre.serializer.

Говорим, что это genre.serializer и это у нас many true.

Что еще надо ему указать?

Ничего, сейчас посмотрим.

И все или не все.

Идем, значит, в наш фильм.

По API.

Идем в... Так, API root, вот movies.

Я перехожу на первый же фильм.

и говорю, что мне нужно с доп.

параметрами.

Бац, ошибка.

Да, потому что я не подумал.

Значит, я делаю вот здесь наследование от вот так.

А, уже сделал.

Fields равно

так, метафилдс, распаковываем сюда просто и докидываем через запятую, дженрес, запятая, так, красота, красота, кстати, где-то мы еще делали так же, но не добавили перенос, точнее, руф там это поправил, вот здесь, и перенос будет добавить, чтобы было красиво,

Вот.

Проверяем, обновляем.

Бац, бац, бац.

Есть.

Подтянулись.

Хорошо.

Какой минус вот такого подхода?

Если я сейчас вот этот... Если я сейчас делаю два фильма... Давайте я сейчас закину новый фильм.

То я не смогу... Да, так.

Так у нас тут это есть.

То я не смогу сейчас без дублирования... Смотрите, я не смогу без дублирования с этим справиться.

Значит, мы идем в каталог, который у нас тут был.

Movie.

Tongue Unchained, да?

Мы говорим...

Выставляем.

2012-2011, то есть 11-12-2012.

И...

Duration 165 минут.

Вот он любит, конечно, снимать.

Rating R. Здесь мы создать пока что связи не можем.

А как мы создаем связи?

Я хочу построить связь.

А как мы создаем связь?

С...

Как мы создаем связь с категориями?

Очень интересный вопрос.

С жанрами, на которые у меня нет ответа.

Не то.

Вот здесь.

Я хочу жанры, чтобы можно было при создании... Ну-ка, здесь есть какой-нибудь read only false.

Вот так, да?

Перехожу... Допустим, хочу обновить его.

Перехожу на второй фильм.

И я хочу сервизатор использовать include равно 1.

Бац, generous есть, и здесь generous нет.

Ну-ка, drf update many to many.

Что, костылями с вами внутри view?

Серьезно?

Это ответ?

Это вопрос.

Ответ.

Реально.

Не, ну это уже издевательство.

Вот тут вот реально лучше уж использовать там в Остапе Джейсонапе, который я показывал на предыдущих эфирах.

Ну потому что, ну типа это идиотизм, я не буду этим заниматься.

Вручную вложенные модельки мне присоединять.

Нет, я сейчас в админке вручную сделаю, конечно.

Вот у нас Movies.

Вот у нас еще один фильм.

И вот здесь это не комедия, но это криминал.

Сохраняем.

Теперь я иду вот сюда в список фильмов.

так, и смотрите, так, movies, вот если я сейчас делаю extended, сейчас мы это сохраним, здравствуйте, добрый вечер, вы как раз на завершение приходите, задавайте вопросы, если есть, мы минут через пять закончим, значит, create, add, add genre serializer to movie,

И сортировочки.

И теперь вот здесь в Views я скажу, что меня в принципе интересует, если Include указан, то вот это мой Detail Serializer.

То есть чтобы у меня не было и то, и другое.

Я просто хочу вот Include, значит все инклюдим.

Сохраняем.

Обновляем.

Смотрите.

Edge Rating подтянут.

Окей.

Generous.

Подтянуто комедия и криминал.

Теперь снова новый фильм.

Криминал полностью подтянут.

Зачем мне два раза вот эта сущность, если я могу ее один раз вернуть?

И в Фастапе Джессенапе у нас так и сделано, что если мы запрашиваем инклюды, то они подтягиваются отдельным массивом.

И если где-то несколько ссылок на этот объект, то он два раза не отображается.

Но так в целом вот мы видим.

Но вот это вот издевательство, что у нас... Давайте мы еще у этого Блэкбокса еще раз спросим.

так movieviewset вот так у нас все можно да воткнуть serializer movie и моделька genre base вот это сейчас я надеюсь что он справится разберется с тем что это за код вообще не хочу просто сейчас ему объяснять каждую строчку

Так, please tell me how to create API post request to add genres to an existing movie in DB using Django REST framework.

Сейчас посмотрим.

Сейчас посмотрим.

Так, что он мне говорит?

Money-to-money field у нас уже есть.

Да, это есть, но я вам просто не показал.

Serializer money required false.

Окей.

Дальше.

Get query set.

Get serializer class мы отдаем.

Action.

Отдельный метод.

Он мне предлагает пилить отдельный метод.

Посмотрите на это.

Зачем он сделал редактирование этого поля?

Он мне предлагает сделать отдельный метод.

Сейчас покрупнее сделаю.

Он мне хочет сказать, что я могу, да, текущий объект получить, получить из запроса, как будут переданы, ну, например, по IDшникам.

Пойти вытащить каждый дженнер отдельно, а это еще куча запросов.

Добавить их сюда.

Если нет, то ошибка.

Рабочая схема?

Рабочая.

Нафига так делать, если many-to-many это популярная задача, и почему бы не сделать встроенный инструмент для этого?

Мне непонятно.

Но так будет отдельная ручка, да, и можно будет так делать.

Но мы это сейчас с вами делать не будем.

Я думаю, можем заканчивать.

У нас криминал по коням.

У нас криминал по коням.

Да, это Андрюха.

Вот, что, закругляемся.

Короче, Джон Крис Фреймворк существует.

И хоть мы за один эфир с вами смогли сделать реально больше, чем мы там сделали за два с половиной эфира, но я все-таки считаю,

что больше гибкости у нас на фастапе JSONAPI, потому что main-to-main у нас там встроенно работает, у нас там инклюды опциональные, как захочешь.

Единственное, чего не хватает, это выборки полей, то есть чтобы запросить только те поля, которые нужны, чтобы из базы они должны доставались.

Этого еще не сделали.

Там вроде работа велась над этим мерч-реквестом, но как будто бы не сделали.

Короче, надо будет посмотреть, потому что я помню, что я даже задачу такую заводил.

Ну, окей.

Вот.

И выходит, что... Ну, в целом, что, нормально работает.

Я код опубликую.

А что нам стоит?

Я сейчас опубликую.

GitHub.

Новый репозиторий.

Так, как это называется?

Example Django DRF Movie Catalog.

Django плюс Django DRF Movie Catalog Example.

Создаем.

И еще я скажу, что он как альтернатива на Example FastAPI JSONAPI.

где у нас там movie каталог ну серьезно я же открывал эту ссылку сегодня буквально окей идем в git remote manage remotes вот он фастапи джи сунапи example movies каталог movie yes а я movie там написал ладно вот найдется найдется вот я скажу что вот на это я уже создал репозиторий создал вот на это мы сейчас и ссылаемся значит коммитим что нам осталось views example

ExtendedSerializerForList2 и импорт удалить лишний да и делаем вот что в Readme пример

примерно fastapi плюс json api это у нас не плюс а через минус делаем 105 json api так вот так это этот код этот код

на джанго плюс джанго rest framework как альтернатива как альтернатива как альтернатива того что мы делали и

на фастапе jsonapi в другом репо вот в другом репозитории вот update readme сейчас отвечу и копируем просто вот это вот

Терминал.

Так.

Соррен, как вы считаете, нужно ли сдротить в алгоритмы задачи типа кодран, лидкод Яндекса?

Что вы об этом думаете?

Если вы хотите пройти с АБС, куда, например, Яндекс, то нужно.

Для работы не нужно, вообще не нужно.

Для реальной работы это не пригодится, именно знание вот этого.

С этих занятий, вот с лидкода, я же много роликов про лидкод снимал.

Вот, все, ссылочка есть, я добавлю в описание.

Сейчас в чатик давайте кину, если у меня есть такая возможность.

Я, ну, вы видели, много роликов снимал про разбор задач, потому что мне было интересно.

Но самое главное, что это помогает, на самом деле, видеть в других местах, что такие алгоритмы, ну, они есть...

Много где.

То есть эти алгоритмы требуются на работе, но это только про базовые.

То есть все, что изи на литкоде, вот оно да.

Да, надо, надо уметь.

Медиум не встречал.

Хард это чисто вот похвастаться, что вы можете хард решить.

Так что нужно ли изи?

Да.

Чтобы вы умели изи решать, хорошо.

Но, опять же, по категории зависит.

Просто фастап пишу.

Ну, пишите на фастапе.

Если вам нужно написать на фастапе, пишите на фастапе.

В Яндекс вас не возьмут, но другие компании, которые принимают по скиллам, а не по алгоритмам, возьмут, если вы реально что-то умеете.

свое приложение, но толком нет с чем был логоритм применять.

Ну и не надо.

Если не надо, мне много лет не надо было, я потом такой, блин, надо попробовать.

Окей, классно посидели.

Я...

Что-то думал, что на джанге, джангрес фреймворк больше гибкости.

Я уже забыл, последний раз на дрэв я писал году в 21 или в 22, наверное.

То есть уже года 3, 3, 3,5 назад я писал на дрэв и подзабыл некоторые вещи.

Вот мы сейчас с вами вспомнили.

Но, смотрите, мы с вами быстро собрали приложение, но все, что выходит за рамки вот 2.1 и 2.1... Кстати, а как мы... А, 2.1 мы с вами делаем, да.

Имя рейтинга мы указываем при создании.

Вот там у нас возникают сложности.

Вот, но так в целом...

Нормально.

Нормально.

Будем заканчивать.

Огромное спасибо, что присоединились.

И если у вас будут какие-либо вопросы, вы знаете, где спросите, приходите в Telegram-чатик.

Ой, а давайте я, раз кто-то досматривает до конца, есть единицы, кому реально было интересно.

Я просто напомню, что если перейти по ссылочке на ролик, опять же, я перейду на канал.

Если я открою вот в этом ролике описание и вот здесь вот ссылка на все мои ресурсы, откроем в инкогнито, чтобы я был не авторизован.

Классно.

Так, YouTube Redirect меня тормозит.

Я можно просто по ссылке перейду?

Нет?

Вот так.

Так вот, есть программа, которую я активно обновляю.

Вот она на степике.

По ссылке будет промокод применяться, но вы можете сначала перейти и закрыть это окошко.

Вот он тут.

применяется чуть он долго вот но потом вы можете заново посылки перейти и посылки мне почему прошу посылки переходить комиссия снижена иначе половину забирает степик и вот а если посылки то мне больше достается так вот

Вот тут написано, что у нас реально будет на курсе.

Это я, ну, это я буду показывать вот так.

Вот все, что написано, вы видите.

В том или ином виде мы пройдем.

Но что сейчас уже доступно, читайте дальше.

Тут написано там бла-бла-бла.

Вот, программа курса.

И вот это, это что уже опубликовано на степике.

Снято больше, чем опубликовано.

Тут, на самом деле, опубликовано... Последний модуль не опубликован.

Вот этот out docker-desktop.

Я сегодня дозаписывал занятие, и я сегодня... завтра буду это опубликовать.

Out не уверен, что опубликую, поэтому stop-урок пока здесь.

Вот, но, короче...

Много скоро опубликую.

Тесты на каждое занятие, иногда по два теста.

Поэтому приходите, активно дополняется.

Если у кого есть какие-то вопросы, я в Телеграмчике обязательно отвечу.

Давайте так, я активно не призываю, но кому интересно было, потому что много людей ждали от меня, вот уже есть.

Когда там будет что посмотреть, потому что алхимию пока мы не разбираем.

Когда будет что посмотреть, алхимия, реальная авторизация, потому что вот эта авторизация пока знакомство базовое с авторизацией.

Там еще несколько занятий.

Короче, когда будет прям уже большой объем, я отдельно анонсирую.

А если кто хочет в раннем доступе, то вот, пожалуйста, потому что там уже, ну, довольно много занятий.

И, конечно же, с выходом новых модулей будет расти цена.

Вот, ну, это если кому вдруг интересно.

Может, вам и неинтересно, то, пожалуйста, ладно.

Я это делаю, потому что мне классно рассказывать.

И формат другой чуть-чуть.

Не как эфиры, не как длинные ролики, там по-другому для себя.

Делаю.

Я там рассказываю, как я бы хотел... Я там даю те знания, которые я бы хотел видеть у своего подчиненного, ну, у своего сотрудника в команде.

То есть если ко мне приходит там условный Джун, я хочу, чтобы он вот те вещи, которые я сейчас показываю, он знал.

Понятно, что не все, невозможно все вот эти вещи знать, но вот что я рассказываю, чтобы основа была.

Вот.

Окей, теперь точно все.

Огромное спасибо, что вообще приходили, были на эфире.

И до новых встреч всегда.

Скоро увидимся.

И всем пока.

Спасибо, пожалуйста.