Pull to refresh

Comments 38

Основная проблема: fastapi - это отличная библиотека для маленьких проектов.

То, что Вы предлагаете непосредственно - фактически сделать какой-то свой фреймворк (то есть систему, которая предписывает, как что делать, куда что класть) на базе связки fastapi+sqlalchemy+alembic+.... Проблема в том, что в результате получается самописный фреймворк со всеми болезнями и недоработками самописных фреймворков.

Тогда вопрос: а почему не взять django, который является готовым фреймворком, и в котором все описанные решения уже сделали и отточили?

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

Действительно, Django — прекрасный "батарейный" фреймворк, где многие решения приняты за разработчика. Если задача — быстро поднять стандартную админку и CRUD, Django часто выигрывает.

Однако я не соглашусь с тезисом, что FastAPI — только для маленьких проектов. Структура, которую я описываю, — это не попытка "написать свой фреймворк", а реализация классической Clean Architecture / Layered Architecture.
Мы не изобретаем велосипед, а используем принцип Composition over Inheritance (композиция вместо наследования), который лежит в основе FastAPI.

Почему не Django?

  1. Асинхронность: FastAPI изначально спроектирован под async/await и высокий I/O. Django async догоняет, но тащит огромный синхронный хвост.

  2. Типизация: Связка Pydantic + FastAPI дает строгую валидацию и автодокументацию на уровне типов Python. В Django работа с типами часто менее прозрачна (магия ORM).

  3. SQLAlchemy 2.0: Она дает гораздо больше контроля над SQL-запросами, чем Django ORM, что критично на высоких нагрузках.

Выбор между ними — это выбор между "Convention over Configuration" (Django) и "Explicit is better than implicit" (FastAPI). Эта статья для тех, кто выбрал второй путь и хочет пройти его правильно».

И текст статьи, и комментарий - генеративщина.

Текст действительно "причесывался" инструментами, чтобы убрать воду и ошибки — это уважение к читателю. Но архитектура, код и подход к разделению слоев — это мой опыт, а не галлюцинации нейросети.Если видите технические ошибки или анти-паттерны в коде — давайте обсуждать их предметно. Я здесь ради этого.

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

А вы можете сказать, что именно в этой статье некачественное, чтобы в будущих статьях я не допускал таких ошибок, заранее благодарен)

Например, то, Рамирез называет Depdency Injection таковым не является. Depends в том виде как он предлагает в документации - получение зависимости, а не внедрение

Ну другой проблемы от тебя и не ожидалось услышать)

Лично меня дико бесят большие буквы после двоеточий, это очень явный признак сгенерированого текста. Почему-то все LLM крайне любят так писать, хоть это и неправильно. В целом, имхо, надо всегда уходить от этого ИИ-шного паттерна вида "пара обобщающих слов: Сама мысль".

Если хочется "и рыбку съесть, и на сосну залезть", можно сделать так: попросить нейронку найти опечатки и огрехи формулировок, но исправлять их уже самостоятельно, предварительно оценив на предмет ложного срабатывания. Так и текст аккуратнее, и авторский стиль полностью сохраняется (я надеюсь, что текст не сгенерирован с нуля, так что этот стиль был). Но, конечно, это более трудоёмко.

Если точнее, то сразу видно почерк Qwen)

это не попытка "написать свой фреймворк", а реализация классической Clean Architecture

Подскажите где в статье реализация классической Clean Architecture?
Вы просто разложили код по папочкам, но это никак не свзяано с https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html

Типизация

Drf-spectacular с типизацией от сериалайзеров и встроенным сваггером - существует.

Chanx для asyncapi(django channels), менее удобный так как требует pydantic модели, в принципе так же существует.

больше контроля над SQL-запросам

Если в проекте джанги существует сырой sql, то что-то уже пошло не так

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

Так FastAPI, это фреймворк для API слоя (остальное считай можно на чистом питоне писать), в то время как Django сразу предписывает архитектуру

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

Потому что Джанго - веб фреймворк, современные приложения редко ограничиваются вебом. Потому что Джанго - active record, заточенный под реляционные бд (коротко - очень ограниченный ORM), потому что Джанго заточен под использование только с его ORM. Потому что Джанго - смесь хороших и сомнительных решений, работающая только за счёт их количества. Потому что Джанго приложение строится вокруг Джанго - а не вокруг нужд бизнеса. Это все приводит к тому, что Джанго хорошо подходит для приложений, являющимися "базами данных с доступом через веб" и только.

Мне как новичку было полезно. Во-первых, делаю свой пет-проект и сверился с вашей статьей и понял, что делаю правильно. Тоже решил максимально разносить сущности. Во-вторых, во много мне помог chatGPT и предложил ~ такое же решение, какое вы описали. Нашел в ваших рассуждениях подтверждения, что такой подход хорошо решает мои задачи.

Спасибо за объективное мнение)

"Я срросил у чатжпт совет, и он дал тот же что и вам. Значит всё хорошо, я спокоен." :)

Всем привет добавлю еще от себя. Во первых: при создании сессии через yield имеет смысл делать на try excpet и при ошибке звать db.rollback; Во вторых аннотаций просто не существует у Вас в коде. В третьих вот статья на том же Хабре годичной давности на Хабр: https://habr.com/ru/articles/848592/ (Не моя), посмотрите пожалуйста, на те модели что Вы предлагаете и что действительно в sqlalchemy 2.0 происходит. В четвертых не раскрыта тема с AsyncAttrs в Base, что очень полезно. Расскажу для чего, когда у Вас есть зависимости в моделях по FK и relationship, и Вам нужно будет вызвать асинхронно ту или иную модель БЕЗ selectinload или joinedload, Вы словите ошибку. Как раз эта штука решает эту проблему при дефолтном lazy. Не сочтите за оскорбление и высокомерие мое, в целом статья не плохая для старта, но есть над чем работать.

Блин, что за люди... Нормально автор написал всё, компактно и понятно новичкам.

у этого "автора" каждая статья написана через нейронку и из-за этого видно всякие артефакты, он даже на комментарии отвечает через нейронку, такие аккаунты надо удалять на хабре, это полный трэш 🤢🤮

Здравствуйте, Какие артефакты? У вас претензии именно из за того что статья некачественная или что? Если есть какие то ошибки в статье или не точности, я готов их обсуждать и редактировать статью)

"Вы" же даже не проверяете что вам нейронка пишет:
# Импортируем Base из нашего файла настроек БД (который мы исправили ранее)

Ранее это когда? В другой статье? В вашем чате с нейронкой? выше этого комментария даже нет упомнимая слова Base.

Почему сразу не брать pyproject.toml вместо requirement.txt? Там как минимум можно задать версии питона на которых будет работать это приложение, и еще много всяких других настроек для всяких тулзов.

Пример того как писать не надо, автор что-то слышал о с4, интересно?

А за использования Depends ещё и для того чтобы базу в роуты засунуть вообще руки отрывать надо

Расскажите как надо. Я без иронии. Мне как относительному новичку интересно.

Ну по правильному разделить на слои, и тащить не сессию в роут а например класс репо (Обозвать можно как угодно, например UserRepo), в нем через инит вызывать сессию (через тот же Depends) и написать функции для класса которые будут работать с сессией. Ручка (эндпоинт) в этом подходе используется только для принятия и валидации данных на выход и выход (DTO), вся работа с БД происходит в классе репо.

Через депендс сессию инжектить не в коем разе нельзя, Depends онли для ручек. Все остальное нужно решать через ioc контейнеры. Над слоем базы данных (реп) должен быть ещё слой с логикой, например юз кейсы

А можете подсказать почему? с UseCase согласен (но опять же дует проект сам по себе, это возможно излишне для маленьких проектов.) Но вот например открываем документацию SQLModel (sqlalchemy + pydantic) по этой ссылке: https://sqlmodel.tiangolo.com/tutorial/fastapi/session-with-dependency/?h=depe#use-the-dependency, в Depends суют сессию и все ок. Хотелось бы понять хотя бы для себя и разобраться, потому что как Я понимаю разрабы одни.

Читаешь заголовок и дисклеймер, превкушаешь: ddd, clear, onion с примерами на fastapi

По тексту: раздел bigger application из официальной документации + парочка приемов и объяснений из других разделов доки.

Для новичков лучше уж эти разделы доки на русский нормально перевести. Те же блоггеры на ютубе пусть и с примерами "todo" лучше данные темы освещают.

Ну простите что статья не оправдала ваши ожидания((

Это лучшая статья для новичков, которую я видел.

models/users.py

primary_key=True создаст констрейнт и уникальный индекс. Дополнительно прописав index=True ты создаешь ещё один индекс. Который тут не нужен.

unique=True создает тебе уникальный индекс, дополнительно index=True создаст тебе ещё один индекс. Не нужный.

по поводу разделения моделей и схем - есть SQLModel

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

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

пу-пу-пу... я конечно не python-разработчик, но при каких сценариях подключение к БД может понадобиться прямиком в роутерах?

Sign up to leave a comment.

Articles