Тёмный

Слоистая Архитектура на FastAPI / Onion Architecture 

Артём Шумейко
Подписаться 28 тыс.
Просмотров 26 тыс.
50% 1

💡 Попробуй онлайн-тренажёр для подготовки к техническому собеседованию: clck.ru/3B5gxT 💡
Предзапись на курс по поиску работы разработчику и техническим навыкам для Middle (FastAPI): forms.gle/Zw7bPnQvTsfekVH47
Забирай роадмап изучения самого востребованного фреймворка на Python - FastAPI здесь: t.me/ArtemShumeikoBot
Репозиторий с кодом: github.com/artemonsh/fastapi-...
Пишу про лайфхаки при поиске работы, рынок труда и способы развития разработчиков в TG канале - подписывайся: t.me/artemshumeiko
Вступай в Python-сообщество (здесь можно задать любой вопрос): t.me/python_community_rus
Поддержать меня и получить ранний доступ к видео можно здесь: boosty.to/artemshumeiko
Превратим плохой код в хороший в 3 простых шага - выделим слой Репозиториев, затем слой Сервисов, а в конце воспользуемся Depends для удобной работы с сервисами.
0:00 - Что вы узнаете сегодня
1:21 - Обзор проекта
4:52 - Проблемы такого подхода
7:35 - К чему мы хотим прийти
10:54 - Пишем Слой репозиториев
20:00 - Пишем Слой сервисов
24:32 - Вынесение сервиса через Depends
26:02 - Резюме
28:33 - Какие проблемы мы не решили?

Опубликовано:

 

19 июн 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 82   
@artemshumeiko
@artemshumeiko 11 месяцев назад
💡 Попробуй онлайн-тренажёр для подготовки к техническому собеседованию: clck.ru/3B5gwP 💡 Забирай роадмап изучения самого востребованного фреймворка на Python - FastAPI здесь: t.me/ArtemShumeikoBot
@skyruptor337
@skyruptor337 11 месяцев назад
Хочу большой курс по sqlalchemy и alembic. Лайк стоит)
@FastAPIChannel
@FastAPIChannel 11 месяцев назад
Хорошо когда есть кто-то, кто за тебя запишет видео по нужной теме)))))
@saitaro
@saitaro 11 месяцев назад
Спасибо за видео! Артём, несколько моментов: 1. В методе TasksService.__init__ в качестве tasks_repo мы ожидаем класс, поэтому аннотируем как type[AbstractRepository], а не AbstractRepository. 2. Имеет смысл сохранять разные версии API в учебных (в этом случае) целях, чтобы можно было сравнить разницу архитектур. 3. Может только мне, но при просмотре видео белая тема жёстко выжигает глаза, особенно ночью. Думаю, лучше использовать тёмную.
@zoyaa9759
@zoyaa9759 10 месяцев назад
Понятно, спокойно, можно и за обедом послушать😊
@adammason482
@adammason482 11 месяцев назад
Спасибо за ролик, обязательно продолжай)
@user-fq4pc7fm2z
@user-fq4pc7fm2z 11 месяцев назад
Спасибо, информативно! по большому счету данную практику можно применить и к другим языкам.
@Maks_travel
@Maks_travel 11 месяцев назад
Спасибо за полезное видео!)
@victorkochkarev2576
@victorkochkarev2576 11 месяцев назад
Срасибо за видео. Полностью согласен с данным подходом. Всё просто пончтно, и так нужно писать проекты.
@begula_chan
@begula_chan 9 месяцев назад
весьма интересно, однозначно лайк!
@denvarenik4873
@denvarenik4873 11 месяцев назад
Познакомился с FastAPI 3 месяца назад. Начав работать сразу обратил внимание, что надо бы как то это все вынести подальше, в результате вышло, что то подобное на луковую архитектуру. Теперь знаю, как это правильно и читабельно упаковать, спасибо! Хотелось бы пример с фильтрацией, который можно так же переиспользовать!
@AS-fk5fw
@AS-fk5fw 11 месяцев назад
Превосходно 💯 даже несмотря на опыт коммерческой разработки на fastapi хочется поддерживать и смотреть с твоего канала для новичков, спасибо !!!
@TechnoBog-ov2mp
@TechnoBog-ov2mp 9 месяцев назад
не канал, а находка 👍
@ez9723
@ez9723 10 месяцев назад
Очень хороший и полезный урок, сам недавно на Java такое реализовывал. Но многие говорят, что это антипатерн и, действительно, сейчас работаю в месте, где проект на Flask и большинство запросов к БД реализованы внутри эндпоинта. Если для каждой из таблиц реализовывать CRUD репозиторий и сервис, то код МКСа вырастет для гигантских размеров
@user-ez9uf9zm3v
@user-ez9uf9zm3v 11 месяцев назад
круто! спасибо!
@dzmitry2408
@dzmitry2408 11 месяцев назад
Подскажи, а нельзя в контроллере использовать что-то вроде: task_service: TaskServece = Depends(TaskService)? А в самом таск сервисе таким же образом получать репо?
@dronss1
@dronss1 11 месяцев назад
Артем, можешь пожалуйста записать видео с различиями между pydantic 1.* и 2.0?
@green1278dramost5
@green1278dramost5 5 месяцев назад
Спасибо за видео! Что ты лумаешь по поводу того, чтобы использовать Протоколы вместо абстрактных базовых классов? Протоколы позволяют задать имена и типы атрибутов класса/экземпляра, параметров методов, а также типы возвращаемых методами значений. Это не получится сделать с помощью ABC.
@Olegt0rr
@Olegt0rr 3 месяца назад
22:51 указана неправильная типизация входного параметра tasks_repo, должно быть Type[AbstractRepository]. Тогда и подсказки для self.tasks_repo корректно будут работать без дублирования типа
@user-xk6ge9xq5o
@user-xk6ge9xq5o 11 месяцев назад
Артем, спасибо за видео! Лучший русскоязычный канал по FastAPI. Подскажите, а в каком слое правильнее обрабатывать исключения связанные с БД? Вроде бы логично в SQLALchemyRepository, ведь мы будем ловить конкретные ошибки SQLAlchemy, но, с другой стороны, мы ведь можем обрабатывать исключения в соответствии с какой-то бизнес-логикой, что кажется правильно держать в сервисном слое?
@AlexandrSpirit
@AlexandrSpirit 10 месяцев назад
В FastApi есть HTTPException. Через него и выводишь ошибку пользователю в формате json
@anton6643
@anton6643 6 месяцев назад
Зависит от того, какие исключения. Если NotFound404 то я, например, бросаю это исключение из репозитория, но с возможностью управлять этим repository.get_one(raise_exception=True). При таком подходе можно заказать получение объекта либо None либо исключение в зависимости от логики. Все остальные исключения можно либо обрабатывать в сервисном слое, либо общим обработчиком fastapi, возвращая 500 server error и логируя ошибку куда-нибудь.
@TheFany666
@TheFany666 10 месяцев назад
Привет! Хмм а когда ты делаешь в find_all методе res = [row[0].to_read_model это не нужно никак обложить уровнем абстракции так же? Т.е такой кейс, ты меняешь алхимию на что то другое, откуда ты знаешь что у тебя модельки соответствуют колу to_read_model внутри реализации SQLNotAlchemyRepository?
@artemshumeiko
@artemshumeiko 10 месяцев назад
Да, конвертацию модели бд в доменную модель приложения лучше вынести в отдельную сущность-класс
@justyar5781
@justyar5781 10 месяцев назад
Хочу большой курс по алхимии и алембик =)
@povladis6940
@povladis6940 11 месяцев назад
ДАВАЙ КУРС ПО АЛХИМИИ И АЛЕМБИКУ, ПО ЧАСУ КАЖДЫЙ ДЕНЬ!
@sergem6860
@sergem6860 10 месяцев назад
Скажите, а тайпхинт AbstractRepository в ините сервиса точно правильный? Судя по тому, что в ините tasks_repo вызывается (как конструктор), его тип не AbstractRepository, а класс этого репозитория (не знаю как правильно указать это в хинте)
@sergem6860
@sergem6860 10 месяцев назад
посмотрел, вроде так и указывается, Type[AbstractRepository]
@user-jo6ui7ue5l
@user-jo6ui7ue5l 5 месяцев назад
А что с join делать? В смысле мы в методах получаем просто id для FK, а хорошо бы полную модельку получить с подтянутыми полями. Если в наследнике репозитория переопределить метод и добавить join, то смысл базового репозитория теряется
@user-uw8hy1lc4p
@user-uw8hy1lc4p 10 месяцев назад
А подскажи можно ли сделать такую же архитектуру как в django с разделением на отдельные приложения или как аналог blueprint во flask, есть у fastapi какое то название для таких приложений и используют ли такой подход? Просто везде, где видел как пишут fast api, обычно всё роуты всех приложений кладут в одну папку routes, по другому с fast api разделение делают
@user-uw8hy1lc4p
@user-uw8hy1lc4p 10 месяцев назад
Я разделил всю логику по отдельным папкам, но как разделить миграции, чтобы они брались из папок с приложениями
@S1beria21
@S1beria21 11 месяцев назад
Что если нужно добавить некую логику присущую только для конкретного репозитория? Например в случае с тасками "удалить каждую вторую таску") Логично будет создавать на репозитории метод TaskRepository.delete_every_second_tasks. Однако дёргать из TaskService такой метод будет неверно (self.tasks_repo.delete_every_second_tasks) ведь абстракция AbstractRepository не имеет такого метода.
@user-uj6wc4jt5d
@user-uj6wc4jt5d 9 месяцев назад
мне кажется ты в TasksService будешь принимать не абстрактный репозиторий, а TasksRepository просто. Ну и в TasksRepository ты можешь наследоватся и просто добавить нужные детали, или переопределить нужный метод.
@alexahdp
@alexahdp 11 месяцев назад
А что насчет типизации? Можно ли получать из базы не абы что, а типизированный обьект/экземпляр класса?
@user-zl5sp9yh1n
@user-zl5sp9yh1n 21 день назад
Для этого нужны дженерики
@best_coozy_dad
@best_coozy_dad Месяц назад
Спасибо за видео! Репозитории же по сути и есть DAO, или я что то путаю?
@artemshumeiko
@artemshumeiko Месяц назад
да, почти одно и то же
@MS-sf3pk
@MS-sf3pk 6 месяцев назад
Каким образом лучше организовать код, если нужно написать специфичный sql запрос, который нужен только для определенного сервиса? Писать функцию внутри сервиса, либо создавать новый репозиторий?
@artemshumeiko
@artemshumeiko 6 месяцев назад
Создавать репу и в ней писать запрос. Затем обращаться к репе внутри сервиса
@goodpins
@goodpins 11 месяцев назад
Насчёт указания типа "абстрактный репо" - тоже такая себе идея. У тебя что, все репозитории одинаковы будут? Смысл тогда в них? Что будешь делать при специфичных задачах?
@user-ye8bz8im3l
@user-ye8bz8im3l 11 месяцев назад
Подскажите как импортировать класс через контекстное меню? Как называется такой плагин?
@artemshumeiko
@artemshumeiko 11 месяцев назад
Вроде как встроен в Visual Studio code Я через CTRL + . вызываю его или правой кнопкой мыши
@artemshumeiko
@artemshumeiko 11 месяцев назад
Возможно кстати это pylance
@user-ye8bz8im3l
@user-ye8bz8im3l 11 месяцев назад
@@artemshumeiko спасибо за ответ. У меня одно из расширений vscode мешало работе. Удалил и все заработало!
@romanbush5164
@romanbush5164 11 месяцев назад
Ахах спасибо Артем, хорошо было бы если бы ты в фишки pidantic посвятил)) и магия , классов настройки , валидации + у нас ещё используется dependancy_injector хорошо было бы осветить его. P.S. шарлотку поставил :DDD
@sergeysergey421
@sergeysergey421 8 месяцев назад
Фабрика еще нужна что бы выбирать конкретную реализацию репозитория
@onikun2120
@onikun2120 3 месяца назад
Очень удобно получилось. Никто не поймет, пока не объяснишь. Люблю такие архитектуры
@user-uw8hy1lc4p
@user-uw8hy1lc4p 10 месяцев назад
Подскажите, кто в курсе, как он импортирует пакеты, чтобы они автоматически вставали вверх на свои места? Че то не попадался мне такой
@artemshumeiko
@artemshumeiko 10 месяцев назад
Должно стоять расширение pylance и дальше при наведении на неимпортированную библиотеку появится всплывающее окошко, в котором можно будет импортировать, либо после наведения нажать CTRL + .
@user-uw8hy1lc4p
@user-uw8hy1lc4p 10 месяцев назад
@@artemshumeiko ок спасибо, ато неудобно либо вспоминать либо копировать с других файлов приходилось
@superpadush
@superpadush 5 месяцев назад
А какой смысл каждый раз при вызове TaskService передавать в него TaskRepository? Разве не логичнее в конструкторе TaskService объявить что-нибудь а-ля self.repo = TaskRepository()?
@s1riys343
@s1riys343 16 дней назад
Буква D из принципов SOLID - Dependency Inversion. В данном случае это значит, что TaskService не должен зависеть от конкретной реализации TaskRepository
@PlagueisMKII
@PlagueisMKII 11 месяцев назад
class Config - тоже устаревший синтаксис. Новый : model_config = ConfigDict(**kwargs)
@artemshumeiko
@artemshumeiko 11 месяцев назад
Спасибо. Во втором видео про архитектуру поправлю это
@suhanoves
@suhanoves 11 месяцев назад
Зачем в абстрактных методах рейзить `NotImplementedError`?
@artyomklg915
@artyomklg915 11 месяцев назад
это нужно на время разработки, чтобы не забыть
@codEnjoyer
@codEnjoyer 11 месяцев назад
На случай, если забудешь реализовать какой-нибудь метод у класса, который наследуется от абстрактного. Тогда при вызове не реализованного метода возникнет эта ошибка
@suhanoves
@suhanoves 11 месяцев назад
@@codEnjoyer советую тогда попробовать не реализовать абстрактный метод у класса наследуемого от ABC и попробовать создать экземпляр)
@superninja2749
@superninja2749 11 месяцев назад
Здравствуйте, будет ли показан подход CBV?
@artemshumeiko
@artemshumeiko 11 месяцев назад
В этом видео нет. В будущих - возможно
@JIJI-zv1qp
@JIJI-zv1qp 6 месяцев назад
а чем она отличается от чистой архитектура Дяди Боба
@JIJI-zv1qp
@JIJI-zv1qp 6 месяцев назад
может про него тоже видос
@artem1736
@artem1736 11 месяцев назад
нужно избавляться от глобальных переменных, в частности от глобального engine и async_session_maker.
@Vladim1r
@Vladim1r 11 месяцев назад
зачем?
@artemshumeiko
@artemshumeiko 11 месяцев назад
engine используется только для одной цели - передачи в фабрику async_sessionmaker. Фабрика в дальнейшем используется для получения сессий, причем значение переменной, хранящей фабрику, нигде не изменяется. Зачем уходить от использования глобальных переменных в данном случае?
@andreyarefev445
@andreyarefev445 11 месяцев назад
Зачем нам множество фабрик сессий в проекте? Зачем тогда нужен будет async_session_maker если он не будет глобальным?
@wwqwqwwqwq
@wwqwqwwqwq 11 месяцев назад
@@andreyarefev445 ты точно понимаешь во что вытекают глобальные переменные? 1. Ты не контролируешь жизненный цикл переменной, например в твоем случае engine (не можешь очистить пул коннектов, выполнив dispose). 2. Весь твой код, буквально весь код, где используется глобальная переменная становится зависим от 1-ой казалось бы переменной, что вытекает в сложную поддержку и тестирование (сложно написать юнит тест, сложно подменять объект, сложно подменять его конфигурацию). 3. Ты привел в пример множества фабрик на проекте, но ты же понимаешь, если ты захочешь в какой-то момент в репозитории иметь подключение к другой БД, следовательно ты должен будешь завести новый engine и async_sessionmaker и подменить их там где нужно, то тебе надо будет менять весь код, который использует предыдущие глобалы. Вот и тебе переиспользование кода, о котором говорится в видео)
@bocik2854
@bocik2854 5 месяцев назад
тишка, ты?
@xesax
@xesax Месяц назад
а это нормально что мы каждый раз будем писать with async_session_maker() ? в каждом методе
@artemshumeiko
@artemshumeiko Месяц назад
лучше объявлять сессию 1 раз уровнем выше. Часто объявляют сессию на уровне эндпоинта/ручки и прокидывают через Depends дальше в те модули, которым нужна сессия для работы с базой данных.
@ammonjerro396
@ammonjerro396 10 месяцев назад
20к за курс? Оо
@artemshumeiko
@artemshumeiko 10 месяцев назад
Это максимальный тариф с собеседованием, консультацией, файлом для подготовки к собеседованию, постоянной поддержкой в телеграмме, созвонами группы и прочим. Есть и другие тарифы с меньшим набором услуг - каждый выбирает под себя :)
@alexanderkashtanov4794
@alexanderkashtanov4794 7 месяцев назад
уже 26к, скоро будет 400 000 минимум
@chelseamurphy6799
@chelseamurphy6799 10 месяцев назад
*promo sm*
@VaeV1ct1s
@VaeV1ct1s 5 месяцев назад
Кажется, не хватает dipendecy injection
@goodpins
@goodpins 11 месяцев назад
Несколько вещей сделаны ужасно: почему в sqlalchemy модели метод для преобразования данный в пидентик? По твоим словам - что будешь делать, когда захочешь поменять orm? Также вопросы что будешь делать, когда некоторые связные модели подгружать не нужно будет Далее про инициализацию репозитория в инициализаторе сервиса + открытие сессии ради каждого метода репозитория - вообще орнул. Тебе не больно, когда ради 2-3 вызовов репозитория в одном сервисе ты будешь открывать на каждый новую сессию алхимии? Пропихнул бы в своем DI сессию ОДНУ и работала бы во время обработки запроса - так экономишь ресурсы
@RasulovENG
@RasulovENG 11 месяцев назад
Предлагаю на английском языке вести чтоб пацаны развивались
@victorkochkarev2576
@victorkochkarev2576 11 месяцев назад
Зачем? Есть много курсов и материалов на английском.
@yevhenKaskov
@yevhenKaskov 10 месяцев назад
на англ. весь интернет забит материалами. А на русском как раз мало. Особенно когда надо понять какие-то абстракции.
@anton6643
@anton6643 6 месяцев назад
Неплохо, но не до конца. Нужно добавить дженерик в объявление абстрактного репозитория и возвращать его в методах.
Далее
100 Дней Хардкора в Valheim | Ashlands
2:08:53
Comedy Moments 🤣 #2
00:25
Просмотров 2,8 млн
Lions Tackle Raging River 😲
00:23
Просмотров 2,6 млн
TypeScript - Быстрый Курс за 70 минут
1:08:00
100 Дней Хардкора в Valheim | Ashlands
2:08:53