Pull to refresh

Comments 23

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

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

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

Примеры:

  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 или в специальных хранилищах секретов, и внедряйте их через шаблоны в конфиги при деплое.

Не соглашусь с Вами полностью.

  1. Django - это Django, он не основан на WSGI: он лишь его поддерживает, ровно как и ASGI. И не "уже заняты" а тогда уж "заняты, но не все". В любом случае использование префикса решает эту проблему. И, да, пришлось придумать, потому что, например, когда мы пишем проект на Django и отдаём его какому-нибудь менеджеру-технарю, он нас отправит обратно с требованием настраивать это приложение на языке python.

  2. Согласен, но здесь одно но: Вам в любом случае придётся проверять все входные данные, которые передаются приложению (потому что так правильно и безопасно). Ваше же правило касается и настроек в Python модуле, которые будут собирать не программисты: их тоже нужно проверять.

  3. Поправьте меня, может я ошибаюсь в силу своего опыта, но переменные среды - это переменные среды (по-другому - переменные окружения). Название говорит самое за себя: я могу сделать их миллион и буду прав. И мне ничего не мешает каждый раз создавать чистое окружения для разных инстансов своего приложения. Тут я могу ошибаться, но секреты улетают только когда злоумышленник получает доступ к боевому серверу (что не исключает возможности украть и Ваш python модуль с настройками); а это уже другой слой защиты и приложения он никак не касается.

  4. Возвращаемся ко второму пункту, читаем Ваши слова и вспоминаем, что мы прежде всего думаем о безопасности. И если сравнивать два приложения: одно, которое запрашивает файлик settings.py, и другое, которое запрашивает переменные окружения (вообще неизвестно откуда и это не важно), то более защищённым будет то, которое настройки просто запрашивает (вместо ожидания целого динамически-исполняемого файлика). Защищённым будет хотя бы потому, что программист, который запрашивает настройки из переменных окружения, создаёт более узкое (и проверяемое) "горлышко" чем то, что есть изначально: settings.py.

Надеюсь, я помог Вам иначе посмотреть на свою точку зрения :)

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

До недавнего времени любил джанго и все проекты начинал с ним - как верно заметил автор - начнешь с 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 нет. Так интереснее.

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

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

Sign up to leave a comment.

Articles

Change theme settings