All streams
Search
Write a publication
Pull to refresh

Comments 38

да тут все — огонь ) шикарное изложение проблем, с которыми мы живем каждый день ) за юмор отдельный плюс

Казалось бы просто не прошел собеседование.

Потрясающе! Сам с половиной проблем постоянно сталкиваюсь и не представляю, что делать.

Примеры:

  1. Опечатка в названии поля relation внутри filter (title => titlr). SomeModel.objects.filter(foreignkey__titlr__contains='some value')

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

  2. Забыл добавить middleware типа permission_required к новому api endpoint, qa это пропустил, получил security problems на проде.

Но хотя бы в django-rest-framework относительно приятней делать views, а в остальном все те же самые боли.

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

Не конфигурируйте Django через переменные среды. Никогда. На это есть достаточно причин.

  1. Django основан на WSGI, WSGI -- это расширение CGI, а в CGI env vars используются для связи с веб-сервером/прокси. Они уже заняты, и по стандарту, и исторически. Неужели надо придумывать ещё какие-то "де факто", чтобы использовать вещь не по назначению?

  2. Переменные среды хранят текст. Для Perl или Bash в этом нет никакой проблемы, но для Python приходится писать парсер/валидатор, который будет дополнительным (и совершенно ненужным) источником ошибок и уязвимостей в вашем приложении.

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

  4. Конфигурация -- это код. Любая достаточно сложная система конфигурирования однажды вырастает в динамический ЯП, иногда даже Тьюринг-полный. Зачем изобретать новый ЯП? Просто пишите конфигурацию на Python.

Как же тогда конфигурировать Django-приложение, если не через файлы среды? Ответ прост: конфигурируйте его через файлы конфигурации.

Если у вас один проект/сервер, храните *.py-файл с секретами вне репозитория, а при установке копируйте его на место (вручную или скриптом, например, Fabric хорош для создания маленьких деплой-скриптов) и импортируйте в основной файл конфигурации.

Если у вас большой проект, то те инструменты для CI/CD, которые вы уже используете, наверняка позволяют шаблонизировать файлы конфигурации. Храните секреты в файлах конфигурации CI/CD или в специальных хранилищах секретов, и внедряйте их через шаблоны в конфиги при деплое.

UFO landed and left these words here

Читал и плакал. Все так и есть.

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

В целом все устраивало, но времена меняются. Пришла асинхронность и джанго просто не успел. Да и не смог бы, с таким-то багажом легаси.

С версии 3 все свернуло не туда. Мало того что для 3 версии надо поправить дофига несовместимостей, так еще и не до конца приделанная асинхронность начинает ругаться на все. Мало того - в 4 версии оно еще больше поломается, но асинхронный ORM так еще и не появится.

Хорошо что появился FastAPI и asgi - для начала хватит, а там, глядишь, новый фреймворк напишут, учтя шишки на этих.

Пришел к аналогичному выводу - использовать в следующих проектах FastAPI. Тем более, что большинство веб-проектов (которые мне приходится писать), используют один из JS фреймворков на стороне клиента, а от бекэнда требуется только API с ограничением доступа.

Мне нравится Торнадо, быстро, очень быстро, и ровно то, что нужно для поддержки JS в темплейтах + асинхронность + алхемия. статик обслуживает nginx. Что ещё нужно для полета в космос?

все батарейки разбора реквестов в наличии.

минус - нет админки (с 10000 строк в м2м поле на выбор ..)

Мне нравятся миграции с default полем, который default только в коде, база об этом дефолте знает только на время выполнения миграции, т.к. в миграции всегда делается DROP DEFAULT;

Это очень "приятно" узнавать, когда джанго в кубе на нескольких инстансах и при добавлении NOT NULL DEFAULT 0 поля и выкатке на первый все ок, а второй начинает падать на INSERT операциях)

И вы, наверно, подумаете: раз jinja шаблоны такие выразительные, значит, за это приходится чем-то платить… Кхм, они ещё и быстрее джанговских

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

>callable default ...не принимает аргументов, поэтому есть только два юз-кейса, когда это нужно: random и datetime.now, который и так уже есть в виде auto_now_add.

А вот auto_now_add лучше вообще не использовать, а как раз указывать datetime.now или timezone.now в default. Почему? Да потому что если использовать auto_now_add, то в тестах не получится создать модель с нужной датой, придётся или использовать батарейки типа time-machine или после создания модели перезаписывать время через .update()

И кстати по поводу "не принимает аргументов", мне кажется что тут наезд на джангу несправедливый, ведь эта проблема решается с помощью functools.partial (такой подход используется во многих батарейках для пайтона, в том числе и в стдлибе)

У меня бекенд одного проекта написан на FastAPI и SQLAlchemy Core, а Django используется только в качестве админки для менеджеров и как инструмент миграций. Если закрыть глаза на дублирование моделей dj -> sqla (сам себя за это пинаю, но изменения происходят нечасто), получается практичный франкенштейн - админка быстро конфигурируется и её легко менять. Натыкался на такие моменты:

1. ORM не поддерживает server default
2. Админка не уважает локальную таймзону клиента при отображении дат, пришлось перегружать base_site.html чтобы сохранять таймзону в cookies, а уже оттуда доставать её мидлварью
3. Виджет для даты неоправданно занимает очень много места. Смотреть я на это не мог, и пришлось перегружать split_datetime.html где <br> заменил на &nbsp;

4. Плагины конфликтуют. Так, django-import-export необъяснимо ломает django-admin-sortable2. К тому же он не работает с django-parler, так что этот import-export пришлось выбросить.

>Нельзя сериализовать лямбду в миграции

А каким образом вы предлагаете сериализовать лямбды?

Я использую AppConfig.ready() для решения проблем с циклическими зависимостями и очень активно - для сильного перекраивания админки (переопределение админок сторонних модулей, русификация и т.п.)

Для меня самое неприятное - процесс контрибьюта в Django. Пробовал сделать PR для отделения логики генерирования одноразовых ссылок от генерации сброса пароля (условно, чтобы можно было генерить ссылки еще и для подтверждения email штатными средствами) - PR отклонили "потому что"

Очень надеюсь, что кто-нибудь их форкнет и начнет развивать немного в другую сторону

FastAPI + VueJS и забыть эти темплейты как дурной сон, как и все остальное. А монга еще и от миграций процентов на 99 избавит.

Учил Django, нифига не понял. Тут мне подбежал на помощь flask и показал как надо. Слепил кучу мини проектиков, тянул базы, и кучу всего.

Но все же позже засел на fastapi(потому что больше апи кодю), и имею в запасе django для более вебовских вещей.

Сталкивался со всем описанным, кроме фласка. Фласк - это некрофилия в условиях популярности aiohttp/fastAPI. С aiohttp работаю, и могу сказать, что разработчик на Django обязан знать сверху один асинхронный фреймворк с независимой ORM. Хотя бы для того, чтобы не писать столь дерзкие слова о Django. Тот же Peewee строит запрос по своим правилам, и там тоже сталкиваешься с проблемами. Тот же Atomic Requests - это не проблема, а деталь, которую ты обязан знать, когда разрабатываешь. И проверять, какой запрос у тебя сформировался в результате последовательного применения .filter(), при условии, что там были joins. Забавно, что Джанга до сих пор фраппирует своих фанатов этими особенностями. Впрочем, peewee вас от такого не спасёт. Там тоже можно применять к кверисету несколько раз .where() или .join(), и финальный запрос может, тоже, содержать ошибки уже иного рода. Эта особенность ORM необходима для того, чтобы вы, как раз, уместили в одну транзакцию содержимое нескольких функций, или даже файлов. Так, например, у вас есть фильтрация внутри views.py и filters.py, и там к кверисету (модел-селекту) последовательно присоединяются условия выборки, причём, в разных методах. И я уже давненько знаю, что следует проверять результирующий запрос. Причём, джанговские методы решения проблем мне нравятся больше, чем в peewee. Например, .extra(), .prefetch() и т.д. Единственно, что джанговская ORM синхронна, но не всегда нужна асинхронность. Каждому флоу - свой юзкейс.

Кстати, в сигнале post_save есть флаг created, а в pre_save нет. Так интереснее.

Но ведь до сохранения Джанго ещё не делало запросов к БД и не может знать существовал объект или нет. Потому и флага нет

Создаем проблему Берем Джанго и героически превозмогаем, когда можно было взять инструменты по отдельности и только те, что нужны. Еще и лучше качеством.

Статья классно иллюстрирует боль живого продакшна, когда “питоновский модуль вроде бы даёт свободу, а по факту - постоянный бардак и ритуальные танцы”.

Django‑CFG - это ровно то, что делает конфигурирование для Django нормальным, “современным” и типобезопасным:

- Настройки становятся не “магическим рулоном из переменных” одним огромным файлом, а строгими Pydantic-классами с валидацией и автокомплитом.

- Ошибки ловятся при запуске, environment-привязка и разделение по сервисам и окружениям из коробки (никакой “settings hell”).

- Появляется структура - каждый модуль за своё, шаблоны и сторонние либы интегрируются без “settings.py”–overload.

- Если добавить ещё auto‑генерацию OpenAPI, поддержку IDE, работу с .env и деплой - становится понятно, насколько устаревший подход в stock‑Django мешает нормальным продуктам жить.

В 2025-м держаться за settings.py - это как ручками настраивать routes.py в 2007-м. Джангисты - кодьте с удовольствием, а не с тоской!

Core dependencies - minimal and essential only

pydantic

PyYAML

click

psycopg2-binary

whitenoise

djangorestframework

django-filter

redis

pyTelegramBotAPI

Ну лол, с таким набором «minimal and essential» сразу до свидания

Понимаю вашу позицию, но позвольте не согласиться с оценкой "лол, до свидания".

Контекст имеет значение

django-cfg - это не "еще одна библиотека", а production-ready фреймворк для быстрого развертывания Django проектов. Сравнивать его с минималистичными утилитами - как сравнивать Ferrari с велосипедом по критерию "простоты".

Разбор "bloat" зависимостей:

Database tier:

- psycopg2-binary - стандарт для PostgreSQL в продакшене

- dj-database-url - 12-factor app принцип

API tier:

- djangorestframework - используют 90% Django проектов

- drf-spectacular - автогенерация OpenAPI документации

- django-filter - фильтрация API (стандарт)

Infrastructure:

- redis + django-redis - кеширование и сессии в продакшене

- whitenoise - статика без nginx (Heroku/Docker стандарт)

Developer Experience:

- click - CLI интерфейс

- rich - красивый вывод в терминале

- django-unfold - современный админ интерфейс

Философия "из коробки"

Вы предлагаете минимализм? Отлично! Тогда используйте django-admin startproject myproject

Но если вам нужен проект, который работает в продакшене через 10 минут после pip install, имеет настроенный API с документацией, поддерживает кеширование, логирование, мониторинг, следует best practices Django/DRF и включает современный админ интерфейс - то добро пожаловать в django-cfg.

Аналогии из мира

Rails тащит ~50 гемов в базовой установке

Laravel включает десятки пакетов по умолчанию

Next.js устанавливает сотни npm зависимостей

Никто не называет их "bloatware", потому что они решают задачу быстрого старта.

Итог

Если вам нужен "minimal and essential" - используйте чистый Django.

Если нужен production-ready проект за 10 минут - используйте django-cfg.

Это разные задачи, разные решения. Критиковать молоток за то, что он не отвертка - странно.

P.S. За месяц разработки django-cfg уже сэкономил кучу времени на настройке проектов. Для меня эти "лишние" зависимости окупились в первую же неделю.

Короче: настраивай Django с нуля, а мы будем деплоить проекты пока ты requirements.txt пишешь 😎

production-ready фреймворк для быстрого развертывания Django проектов

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

Если нужен production-ready проект за 10 минут

Заточенный под ваши личные нужды и хотелки. Из чего следует, что использовать django-cfg не будет никто кроме вас (кстати к django-revolution это тоже относится)

Никто не называет их "bloatware"

Я называю и принципиально не использую (да и в общем-то сам Django тоже bloatware на самом деле, я бы его распилил на десяток пакетов поменьше)

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

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

К psycopg2, redis и django-filter вообще какие у вас претензии? Все остальные (кроме TelegramBot) вполне правильно объяснены. Может быть вы хотите REST API писать самостоятельно без DRF?

Ну телеграм там скорее опциональный модуль, его можно и не использовать. Но для отладки очень иногда помогает, когда "батл нейк" совсем уж сложный.
Видимо @andreymal просто любит писать "на коленях", без сторонних либ, все сам)

psycopg2

На моём проде MySQL и я не вижу существенных причин менять его на постгрес

redis

memcached никто не отменял

django-filter

На первый взгляд выглядит потенциально полезным, но зачем его навязывать как обязательную зависимость?

REST API

Ужасен и принципиально не делаю в своих проектах, я предпочитаю что-нибудь RPC-подобное, а индустрия вообще предпочитает GraphQL

без DRF

Я так и не понял зачем мне DRF, ни в одном моём проекте его нет

Не то чтобы я придираюсь к каждой строчке, но хочется ещё раз ответить.

На моём проде MySQL и я не вижу существенных причин менять его на постгрес

Я вижу это как один из драйверов БД, не принципиально какой. Уже есть, действительно, третья версия. Может быть oracle, но в любом случае, движок для базы вы всё равно поставите. Берём.

memcached никто не отменял

Ок, это тоже ваш выбор, хотя я беру Redis. Memcached тоже сторонний пакет.

django-filter - ок, это вкусовщина, согласен. Он известен уже больше 10 лет, но я, в последнее время, тоже его не использую. Не обязателен.

DRF, REST API, GraphQL, RPC, gRPC - неважно. Суть в том, что для GraphQL вы тоже не будете чистый django использовать, а по зависимостям там тащится еще пакетов с десяток. Pydantic здесь ещё цветочки будет.

Ну лол, с таким набором «minimal and essential» сразу до свидания

Вот именно это ваше презрительное замечание и вызывает вопросы. Что же для вас тогда будет minimal and essential для стандартного production-ready проекта?

Проблема не в самом факте установки дополнительных пакетов, а в том, что django-cfg навязывает вполне конкретный их набор и запрещает его пользователям иметь своё собственное мнение относительно «minimal and essential»

Для проекта, который «делает конфигурирование для Django нормальным», единственная «minimal and essential» зависимость — это сам Django и больше ничего (при этом он упомянут как «peer dependency» и вообще не указан в зависимостях, лол). Ну может ещё pydantic, но тоже спорно (но сейчас не об этом). Все остальные постгресы, редисы и дрфы должны быть максимум в опциональных зависимостях для подтягивания аннотаций типов, а не навязываться

Ну а если это подаётся как «production-ready фреймворк для быстрого развертывания Django проектов», то его будут использовать только те, чьё мнение о «production-ready» на 100% совпадает с мнением автора — то есть скорее всего только сам автор

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

Вы же говорите о конкретно этом пакете django-cfg и его зависимостях, которые там гвоздями прибиты. Ну, именно с этим у меня особых разногласий с вами нет, я согласен что именно с "cfg" они мало имеют общего. Однако, я на него смотрю только как на личный темплейт @markolofsen, который был приведен только для примера отдельной фичи, а не реклама использования. У меня тоже есть такие шаблоны проектов. Да и у всех есть, наверное.

Думаю, вы не до конца поняли концепцию проекта.

Вот согласен.

  1. Очень личный список зависимостей, при этом можно было бы сделать что-то вроде pip install django-cfg[postgres,redis] через pyproject optional dependencies, чтобы выбирать зависимости самому, но нет.

  2. psycopg2 в зависимостях, хотя уже есть третья версия. Ещё, например, зачем мне django-filter, если я не фильтрую в API, или есть у меня вообще нет API и не нужен?

  3. psycopg2-binary вот обязательно нужен, чтобы проверять типы переменных в settings.py - я правильно понял? Почему это обязательная зависимость?

  4. Почему "3-line configuration that handles everything", если в итоге всё равно ручками нужно свои настройки прописывать, просто теперь в классах (config.py::MyConfig)?

  5. Если главная цель - типобезопасность настроек, то я бы использовал инструмент для типобезопасного питона - mypy. Есть же стабы для того же django, почему бы не допилить их для settings.py как-нибудь?

  6. feature comparison - Поздравляю, вы создали монстра-надстройку над предыдущем монстром.

По-поводу редиса согласен, постараемся учесть. Спасибо за замечение.

Если вы не используете django drf, то django-filter вам конечно же не нужен. Но тогда зачем вам django? Просто базу админить?

Согласен про psycopg3 - поправим тоже!

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

Sign up to leave a comment.

Articles