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

  Рет қаралды 32,581

Артём Шумейко

Артём Шумейко

Күн бұрын

Пікірлер: 91
@artemshumeiko
@artemshumeiko Жыл бұрын
💡 Попробуй онлайн-тренажёр для подготовки к техническому собеседованию: clck.ru/3B5gwP 💡 Забирай роадмап изучения самого востребованного фреймворка на Python - FastAPI здесь: t.me/ArtemShumeikoBot
@skyruptor337
@skyruptor337 Жыл бұрын
Хочу большой курс по sqlalchemy и alembic. Лайк стоит)
@FastAPIChannel
@FastAPIChannel Жыл бұрын
Хорошо когда есть кто-то, кто за тебя запишет видео по нужной теме)))))
@saitaro
@saitaro Жыл бұрын
Спасибо за видео! Артём, несколько моментов: 1. В методе TasksService.__init__ в качестве tasks_repo мы ожидаем класс, поэтому аннотируем как type[AbstractRepository], а не AbstractRepository. 2. Имеет смысл сохранять разные версии API в учебных (в этом случае) целях, чтобы можно было сравнить разницу архитектур. 3. Может только мне, но при просмотре видео белая тема жёстко выжигает глаза, особенно ночью. Думаю, лучше использовать тёмную.
@TechnoBog-ov2mp
@TechnoBog-ov2mp Жыл бұрын
не канал, а находка 👍
@adammason482
@adammason482 Жыл бұрын
Спасибо за ролик, обязательно продолжай)
@zoyaa9759
@zoyaa9759 Жыл бұрын
Понятно, спокойно, можно и за обедом послушать😊
@АлександрСосо-щ1б
@АлександрСосо-щ1б Жыл бұрын
Спасибо, информативно! по большому счету данную практику можно применить и к другим языкам.
@begula_chan
@begula_chan Жыл бұрын
весьма интересно, однозначно лайк!
@ez9723
@ez9723 Жыл бұрын
Очень хороший и полезный урок, сам недавно на Java такое реализовывал. Но многие говорят, что это антипатерн и, действительно, сейчас работаю в месте, где проект на Flask и большинство запросов к БД реализованы внутри эндпоинта. Если для каждой из таблиц реализовывать CRUD репозиторий и сервис, то код МКСа вырастет для гигантских размеров
@СтаниславНектов
@СтаниславНектов Ай бұрын
Ну так добро пожаловать на энтерпрайз уровень. Обычно когда много таблиц, большая часть CRUDа создаётся копипастой. А детали реализации вам так и так писать, разница лишь в том, где этот код лежать будет, только в одном случае у вас везде стандартный crud, а в другом "Вась, не помнишь где мы это написали?" И это, почему то люди предпочитают джипы и кроссоверы, а не малолитражки, хотя последние и проще в производстве.
@AS-fk5fw
@AS-fk5fw Жыл бұрын
Превосходно 💯 даже несмотря на опыт коммерческой разработки на fastapi хочется поддерживать и смотреть с твоего канала для новичков, спасибо !!!
@Maks_travel
@Maks_travel Жыл бұрын
Спасибо за полезное видео!)
@denvarenik4873
@denvarenik4873 Жыл бұрын
Познакомился с FastAPI 3 месяца назад. Начав работать сразу обратил внимание, что надо бы как то это все вынести подальше, в результате вышло, что то подобное на луковую архитектуру. Теперь знаю, как это правильно и читабельно упаковать, спасибо! Хотелось бы пример с фильтрацией, который можно так же переиспользовать!
@linust5892
@linust5892 Ай бұрын
1. Переопределяешь сигнатуры дочерних классов, что не ок. 2. Не показал, как работаешь с селектом и перегоняешь модели между слоями
@victorkochkarev2576
@victorkochkarev2576 Жыл бұрын
Срасибо за видео. Полностью согласен с данным подходом. Всё просто пончтно, и так нужно писать проекты.
@JIJI-zv1qp
@JIJI-zv1qp 13 күн бұрын
А чем отличается onion architecture от clean architecture? Там же еще есть mvc, mvp, mvt и возможно что то еще
@teawithoutdonuts31
@teawithoutdonuts31 4 ай бұрын
Какой-то Java EE. Нет никаких проблем писать sql в эндпоинтах. Он как раз гораздо понятнее и нагляднее там сидит. В крайнем случае для длинных запросов можно вынести выражение в отдельный модуль. Когда у вас с фронта просят ручки со вложенными сущностями вам нужно делать joinedload/selectinload. Где-то вам нужен User+Tasks, где-то только User. Вы на каждый такой вариант будете делать по функции в репозитории? Или передавать опции отдельным параметром, ещё больше всё усложняя? Модели и схемы можно очень быстро посмотреть одним кликом из эндпоинта, а вот прыгать по ORM надстройкам кастомным - это как раз разбираться нужно. Ну и по поводу притянутой за уши задачи уровня "смены sqlalchemy" - такое не происходит почти никогда. Да и на что? Вы скорее на другой язык переписывать будете.
@СтаниславНектов
@СтаниславНектов Ай бұрын
Никто не может запретить писать плохо, каждый человек или команда пишет как ему удобно. Можно вообще все в одном файле написать, так просто сверх наглядно будет, я считаю. 😂 А уж как навариться на поддержке потом можно будет, долгими месяцами пытаясь найти баг - просто мечта. 😊 При многослойной архитектуре вы не модель меняете в ручках, а вызов функции сервиса, или сервис правите не трогая ручку вообще. Работу со вложенными сущностями да и вообще при объединении данных нескольких таблиц вам так и так где то писать надо вне зависимости от архитектуры и ее наличия в принципе 😂 , можно конечно навалить все в эндпоинты, компьютер все стерпит.
@povladis6940
@povladis6940 Жыл бұрын
ДАВАЙ КУРС ПО АЛХИМИИ И АЛЕМБИКУ, ПО ЧАСУ КАЖДЫЙ ДЕНЬ!
@АлександрМайстришин-д7х
@АлександрМайстришин-д7х Жыл бұрын
круто! спасибо!
@СергейКим-ь9с
@СергейКим-ь9с Жыл бұрын
Артем, спасибо за видео! Лучший русскоязычный канал по FastAPI. Подскажите, а в каком слое правильнее обрабатывать исключения связанные с БД? Вроде бы логично в SQLALchemyRepository, ведь мы будем ловить конкретные ошибки SQLAlchemy, но, с другой стороны, мы ведь можем обрабатывать исключения в соответствии с какой-то бизнес-логикой, что кажется правильно держать в сервисном слое?
@AlexandrSpirit
@AlexandrSpirit Жыл бұрын
В FastApi есть HTTPException. Через него и выводишь ошибку пользователю в формате json
@anton6643
@anton6643 10 ай бұрын
Зависит от того, какие исключения. Если NotFound404 то я, например, бросаю это исключение из репозитория, но с возможностью управлять этим repository.get_one(raise_exception=True). При таком подходе можно заказать получение объекта либо None либо исключение в зависимости от логики. Все остальные исключения можно либо обрабатывать в сервисном слое, либо общим обработчиком fastapi, возвращая 500 server error и логируя ошибку куда-нибудь.
@Olegt0rr
@Olegt0rr 8 ай бұрын
22:51 указана неправильная типизация входного параметра tasks_repo, должно быть Type[AbstractRepository]. Тогда и подсказки для self.tasks_repo корректно будут работать без дублирования типа
@iJaVolo
@iJaVolo 22 күн бұрын
А почему в абстрактном классе в методах нет self, а просто пустые скобки? А что будет если добавить? Мне просто pycharm красным подчёркивает, но в ошибку не выпадает
@green1278dramost5
@green1278dramost5 10 ай бұрын
Спасибо за видео! Что ты лумаешь по поводу того, чтобы использовать Протоколы вместо абстрактных базовых классов? Протоколы позволяют задать имена и типы атрибутов класса/экземпляра, параметров методов, а также типы возвращаемых методами значений. Это не получится сделать с помощью ABC.
@МурадАхмедов-ч1с
@МурадАхмедов-ч1с Жыл бұрын
А подскажи можно ли сделать такую же архитектуру как в django с разделением на отдельные приложения или как аналог blueprint во flask, есть у fastapi какое то название для таких приложений и используют ли такой подход? Просто везде, где видел как пишут fast api, обычно всё роуты всех приложений кладут в одну папку routes, по другому с fast api разделение делают
@МурадАхмедов-ч1с
@МурадАхмедов-ч1с Жыл бұрын
Я разделил всю логику по отдельным папкам, но как разделить миграции, чтобы они брались из папок с приложениями
@ЕвгенийБондарев-э1ц
@ЕвгенийБондарев-э1ц 9 ай бұрын
А что с join делать? В смысле мы в методах получаем просто id для FK, а хорошо бы полную модельку получить с подтянутыми полями. Если в наследнике репозитория переопределить метод и добавить join, то смысл базового репозитория теряется
@TheFany666
@TheFany666 Жыл бұрын
Привет! Хмм а когда ты делаешь в find_all методе res = [row[0].to_read_model это не нужно никак обложить уровнем абстракции так же? Т.е такой кейс, ты меняешь алхимию на что то другое, откуда ты знаешь что у тебя модельки соответствуют колу to_read_model внутри реализации SQLNotAlchemyRepository?
@artemshumeiko
@artemshumeiko Жыл бұрын
Да, конвертацию модели бд в доменную модель приложения лучше вынести в отдельную сущность-класс
@dronss1
@dronss1 Жыл бұрын
Артем, можешь пожалуйста записать видео с различиями между pydantic 1.* и 2.0?
@dzmitry2408
@dzmitry2408 Жыл бұрын
Подскажи, а нельзя в контроллере использовать что-то вроде: task_service: TaskServece = Depends(TaskService)? А в самом таск сервисе таким же образом получать репо?
@best_coozy_dad
@best_coozy_dad 6 ай бұрын
Спасибо за видео! Репозитории же по сути и есть DAO, или я что то путаю?
@artemshumeiko
@artemshumeiko 6 ай бұрын
да, почти одно и то же
@onikun2120
@onikun2120 8 ай бұрын
Очень удобно получилось. Никто не поймет, пока не объяснишь. Люблю такие архитектуры
@S1beria21
@S1beria21 Жыл бұрын
Что если нужно добавить некую логику присущую только для конкретного репозитория? Например в случае с тасками "удалить каждую вторую таску") Логично будет создавать на репозитории метод TaskRepository.delete_every_second_tasks. Однако дёргать из TaskService такой метод будет неверно (self.tasks_repo.delete_every_second_tasks) ведь абстракция AbstractRepository не имеет такого метода.
@maxrudn
@maxrudn Жыл бұрын
мне кажется ты в TasksService будешь принимать не абстрактный репозиторий, а TasksRepository просто. Ну и в TasksRepository ты можешь наследоватся и просто добавить нужные детали, или переопределить нужный метод.
@Chris-dx7oi
@Chris-dx7oi 2 ай бұрын
Так, а ты решил этот вопрос для себя? Можешь поделиться, если да?
@MS-sf3pk
@MS-sf3pk 11 ай бұрын
Каким образом лучше организовать код, если нужно написать специфичный sql запрос, который нужен только для определенного сервиса? Писать функцию внутри сервиса, либо создавать новый репозиторий?
@artemshumeiko
@artemshumeiko 11 ай бұрын
Создавать репу и в ней писать запрос. Затем обращаться к репе внутри сервиса
@sergeysergey421
@sergeysergey421 Жыл бұрын
Фабрика еще нужна что бы выбирать конкретную реализацию репозитория
@goodpins
@goodpins Жыл бұрын
Насчёт указания типа "абстрактный репо" - тоже такая себе идея. У тебя что, все репозитории одинаковы будут? Смысл тогда в них? Что будешь делать при специфичных задачах?
@Chris-dx7oi
@Chris-dx7oi 2 ай бұрын
А какую альтернативу можешь предложить? Вместо указания абстрактного типа репозитория указывать конкретную реализацию? Думаю это может быть нарушением принципа D в SOLID, может есть ещё какие-то варианты или вообще иной подход к построению архитектуры?
@justyar5781
@justyar5781 Жыл бұрын
Хочу большой курс по алхимии и алембик =)
@sergem6860
@sergem6860 Жыл бұрын
Скажите, а тайпхинт AbstractRepository в ините сервиса точно правильный? Судя по тому, что в ините tasks_repo вызывается (как конструктор), его тип не AbstractRepository, а класс этого репозитория (не знаю как правильно указать это в хинте)
@sergem6860
@sergem6860 Жыл бұрын
посмотрел, вроде так и указывается, Type[AbstractRepository]
@superpadush
@superpadush 10 ай бұрын
А какой смысл каждый раз при вызове TaskService передавать в него TaskRepository? Разве не логичнее в конструкторе TaskService объявить что-нибудь а-ля self.repo = TaskRepository()?
@s1riys343
@s1riys343 5 ай бұрын
Буква D из принципов SOLID - Dependency Inversion. В данном случае это значит, что TaskService не должен зависеть от конкретной реализации TaskRepository
@alexahdp
@alexahdp Жыл бұрын
А что насчет типизации? Можно ли получать из базы не абы что, а типизированный обьект/экземпляр класса?
@НиколайРюмин-й6и
@НиколайРюмин-й6и 5 ай бұрын
Для этого нужны дженерики
@romanbush5164
@romanbush5164 Жыл бұрын
Ахах спасибо Артем, хорошо было бы если бы ты в фишки pidantic посвятил)) и магия , классов настройки , валидации + у нас ещё используется dependancy_injector хорошо было бы осветить его. P.S. шарлотку поставил :DDD
@Johny-d4v
@Johny-d4v Жыл бұрын
Подскажите как импортировать класс через контекстное меню? Как называется такой плагин?
@artemshumeiko
@artemshumeiko Жыл бұрын
Вроде как встроен в Visual Studio code Я через CTRL + . вызываю его или правой кнопкой мыши
@artemshumeiko
@artemshumeiko Жыл бұрын
Возможно кстати это pylance
@Johny-d4v
@Johny-d4v Жыл бұрын
@@artemshumeiko спасибо за ответ. У меня одно из расширений vscode мешало работе. Удалил и все заработало!
@suhanoves
@suhanoves Жыл бұрын
Зачем в абстрактных методах рейзить `NotImplementedError`?
@artyomklg915
@artyomklg915 Жыл бұрын
это нужно на время разработки, чтобы не забыть
@codEnjoyer
@codEnjoyer Жыл бұрын
На случай, если забудешь реализовать какой-нибудь метод у класса, который наследуется от абстрактного. Тогда при вызове не реализованного метода возникнет эта ошибка
@suhanoves
@suhanoves Жыл бұрын
@@codEnjoyer советую тогда попробовать не реализовать абстрактный метод у класса наследуемого от ABC и попробовать создать экземпляр)
@JIJI-zv1qp
@JIJI-zv1qp 11 ай бұрын
а чем она отличается от чистой архитектура Дяди Боба
@JIJI-zv1qp
@JIJI-zv1qp 11 ай бұрын
может про него тоже видос
@PlagueisMKII
@PlagueisMKII Жыл бұрын
class Config - тоже устаревший синтаксис. Новый : model_config = ConfigDict(**kwargs)
@artemshumeiko
@artemshumeiko Жыл бұрын
Спасибо. Во втором видео про архитектуру поправлю это
@DangerSpliff
@DangerSpliff 15 күн бұрын
Репозиторий не должен управлять транзакцией
@xesax
@xesax 6 ай бұрын
а это нормально что мы каждый раз будем писать with async_session_maker() ? в каждом методе
@artemshumeiko
@artemshumeiko 6 ай бұрын
лучше объявлять сессию 1 раз уровнем выше. Часто объявляют сессию на уровне эндпоинта/ручки и прокидывают через Depends дальше в те модули, которым нужна сессия для работы с базой данных.
@МурадАхмедов-ч1с
@МурадАхмедов-ч1с Жыл бұрын
Подскажите, кто в курсе, как он импортирует пакеты, чтобы они автоматически вставали вверх на свои места? Че то не попадался мне такой
@artemshumeiko
@artemshumeiko Жыл бұрын
Должно стоять расширение pylance и дальше при наведении на неимпортированную библиотеку появится всплывающее окошко, в котором можно будет импортировать, либо после наведения нажать CTRL + .
@МурадАхмедов-ч1с
@МурадАхмедов-ч1с Жыл бұрын
@@artemshumeiko ок спасибо, ато неудобно либо вспоминать либо копировать с других файлов приходилось
@artem1736
@artem1736 Жыл бұрын
нужно избавляться от глобальных переменных, в частности от глобального engine и async_session_maker.
@скриптослав
@скриптослав Жыл бұрын
зачем?
@artemshumeiko
@artemshumeiko Жыл бұрын
engine используется только для одной цели - передачи в фабрику async_sessionmaker. Фабрика в дальнейшем используется для получения сессий, причем значение переменной, хранящей фабрику, нигде не изменяется. Зачем уходить от использования глобальных переменных в данном случае?
@andreyarefev445
@andreyarefev445 Жыл бұрын
Зачем нам множество фабрик сессий в проекте? Зачем тогда нужен будет async_session_maker если он не будет глобальным?
@wwqwqwwqwq
@wwqwqwwqwq Жыл бұрын
@@andreyarefev445 ты точно понимаешь во что вытекают глобальные переменные? 1. Ты не контролируешь жизненный цикл переменной, например в твоем случае engine (не можешь очистить пул коннектов, выполнив dispose). 2. Весь твой код, буквально весь код, где используется глобальная переменная становится зависим от 1-ой казалось бы переменной, что вытекает в сложную поддержку и тестирование (сложно написать юнит тест, сложно подменять объект, сложно подменять его конфигурацию). 3. Ты привел в пример множества фабрик на проекте, но ты же понимаешь, если ты захочешь в какой-то момент в репозитории иметь подключение к другой БД, следовательно ты должен будешь завести новый engine и async_sessionmaker и подменить их там где нужно, то тебе надо будет менять весь код, который использует предыдущие глобалы. Вот и тебе переиспользование кода, о котором говорится в видео)
@bocik2854
@bocik2854 10 ай бұрын
тишка, ты?
@ammonjerro396
@ammonjerro396 Жыл бұрын
20к за курс? Оо
@artemshumeiko
@artemshumeiko Жыл бұрын
Это максимальный тариф с собеседованием, консультацией, файлом для подготовки к собеседованию, постоянной поддержкой в телеграмме, созвонами группы и прочим. Есть и другие тарифы с меньшим набором услуг - каждый выбирает под себя :)
@izpodvypodwerta
@izpodvypodwerta 11 ай бұрын
уже 26к, скоро будет 400 000 минимум
@goodpins
@goodpins Жыл бұрын
Несколько вещей сделаны ужасно: почему в sqlalchemy модели метод для преобразования данный в пидентик? По твоим словам - что будешь делать, когда захочешь поменять orm? Также вопросы что будешь делать, когда некоторые связные модели подгружать не нужно будет Далее про инициализацию репозитория в инициализаторе сервиса + открытие сессии ради каждого метода репозитория - вообще орнул. Тебе не больно, когда ради 2-3 вызовов репозитория в одном сервисе ты будешь открывать на каждый новую сессию алхимии? Пропихнул бы в своем DI сессию ОДНУ и работала бы во время обработки запроса - так экономишь ресурсы
@superninja2749
@superninja2749 Жыл бұрын
Здравствуйте, будет ли показан подход CBV?
@artemshumeiko
@artemshumeiko Жыл бұрын
В этом видео нет. В будущих - возможно
@VaeV1ct1s
@VaeV1ct1s 9 ай бұрын
Кажется, не хватает dipendecy injection
@chelseamurphy6799
@chelseamurphy6799 Жыл бұрын
*promo sm*
@RasulovENG
@RasulovENG Жыл бұрын
Предлагаю на английском языке вести чтоб пацаны развивались
@victorkochkarev2576
@victorkochkarev2576 Жыл бұрын
Зачем? Есть много курсов и материалов на английском.
@yevhenKaskov
@yevhenKaskov Жыл бұрын
на англ. весь интернет забит материалами. А на русском как раз мало. Особенно когда надо понять какие-то абстракции.
@anton6643
@anton6643 10 ай бұрын
Неплохо, но не до конца. Нужно добавить дженерик в объявление абстрактного репозитория и возвращать его в методах.
У вас там какие таланты ?😂
00:19
Карина Хафизова
Рет қаралды 20 МЛН
The Singing Challenge #joker #Harriet Quinn
00:35
佐助与鸣人
Рет қаралды 17 МЛН
FastAPI ТОП Библиотек и Расширений [2024]
12:21
Артём Шумейко
Рет қаралды 20 М.
Чистая архитектура и Domain-Driven Design
1:55:56
Чистая архитектура ASP.NET Core 7
25:20
Excalib
Рет қаралды 13 М.
SENIOR on JUNIOR Javascript Developer interview
26:35
BELOV
Рет қаралды 339 М.