Как стать автором
Обновить

Комментарии 10

Благодарю, познавательно.

Вообще не понял кто был джуном в этой истории :)

Не джуном же — стажёром. А стажёром может быть любой. При смене работы например.
Статья хорошая и интересная. Побольше бы таких на хабр

Привет @ipakeev. Хорошая история, интересно было посмотреть, как кто то еще оптимизирует запросы. Успехов в изучении Django, в ней столько еще багов не исправлено :)

После прочтения, спустя некоторое время вернулся к статье, осознавая, что что то в статье меня смущает (зануда_mode = on). Стал искать:

В списке оптимизаци - куда делся defer? Defer - это зеркальный брат only, и всегда есть четкий признак, что лучше использовать. Если в only полей больше половины, тогда defer. А то какая то однобокая оптимизация у вас получается.

В DRF можно создать сериализаторы а-ля GRAPHQL, и наоборот. Потому не стоит априори полагать что если REST-API то можно нахардкодить. Не согласен. Стоит всегда хорошо писать.

Нашел, кстати, что сильно смутило. Эта фраза: "Так как информация о модели статична, ее можно кэшировать при помощи _your_cache_lib_". Не поверишь. Разрабы класса Model в Django давным давно так же подумали. В любой django модели есть представленные тобой кеши полей. Причем уже разделенные по типам (related/not_related/m2m). Посмотри Model._meta.related_objects, Model._meta.private_fields (это generic relation), Model._meta.many_to_many и т.п. Получается, что, например, _get_model_fields_to_select в твоем коде можно упростить.

Если использовать знания про Django, то упрощать можно много где. Но главное то, что многое упущено:

Генерация field.name через имя related model не сработает, если в поле переопределено related_name или в модели переопределено default_related_name.

У прокси моделей нет полей. Оптимизация не сработает, если в коде не оспользовать обращение к concrete_model вместо прокси. История про pk только подчеркивает, что автор так и не понял что не только с PK полем проблема.

Второй баг, это не баг. defer/only не делает join нужных таблиц. потому не "наблюдается огромное количество запросов", а проявляется проблема O(n+1) запросов (N+1 Queries Problem) на этапе сериализации. Решается, например, добавлением тупого фильтра filter(mythroughmodel__mymodel__pk__isnull=False) или приджойном нужной таблицы вручную но это работа с недокументированным queryset.query

Ещё раз желаю успехов в изучении Django.

Благодарю за замечания и развернутый ответ.

В списке оптимизаци - куда делся defer?

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

В DRF можно создать сериализаторы а-ля GRAPHQL

В DRF пока не силен, буду копать.

Не поверишь. Разрабы класса Model в Django давным давно так же подумали.

Информация о полях модели нам нужна в определенном формате, поэтому и применяем кэширование, чтобы каждый раз не итерироваться по атрибутам _meta.
Кстати, m2m поле указывается в Model._meta.many_to_many, а в Model._meta.fields не указывается (или не всегда), хотя там у каждого поля есть булевый признак many_to_many.

Генерация field.name через имя related model не сработает, если в поле переопределено related_name или в модели переопределено default_related_name.

У нас практически в каждой модели указан related_name, и всё работает. Попробовал переопределить default_related_name - снова всё работает. Единственный момент, когда не происходит оптимизация, это переопределение related_query_name, но этот способ для тех, кто точно хочет всё сломать.

Оптимизация не сработает, если в коде не оспользовать обращение к concrete_model вместо прокси.

Не понял, почему оптимизация не должна срабатывать. В проекте наблюдаем одинаково оптимальное количество запросов при обращении что к прокси, что к concrete_model.

Второй баг, это не баг. defer/only не делает join нужных таблиц.

Про join и речи не было. "огромное количество запросов" - это симптом, с которым нужно было разобраться. При реверсивном внешнем ключе возникает такая проблема, а, так сказать, при прямом внешнем ключе, всё работает так, как и ожидается (то есть автоматически достается pk).

На мой взгляд, одной из самых крутых особенностей Django является Django ORM, который преобразует запрос в базу данных из Python-кода в язык SQL.

Обычно хвалят алхимию)

Я тоже сначала восхищался алхимией, пока не стал работать с Django ORM. Мем в блоке P.S. тому подтверждение)

@GothicJS Если отстраниться от собственного нежного отношения к <любой любимый орм>, то мы трое не правы. Алчеми вырвавшись вперёд в 2015-16, уже в 2019 уступала Джанго в гибкости. И на этом фоне всех начала обгонять черепаха. Как по позитивным отзывам так и по скорости и применению в проектах. Однако я не ожидал, что расклад настолько поменялся: https://github.com/tortoise/orm-benchmarks.

Думаю, когда это произойдет, для меня выбор будет очевидным. 

ИМХО, не скоро ещё async ORM Django станет юзабельным. Сначала будет исправление тонны багов, потом оптимизация, ну и синтаксис, конечно, придумали убогий.

Надо было при переходе на 4ю мажорную версию, когда была возможность сделать именно мажорные (обратно не совместимые) изменения переделывать ORM, а теперь они связаны обратной совместимостью, так что весь async будет завозиться на "кастылях", так что по нормальному async ORM запилят только в версии 5 Django.

Очень любил Django, до того как в Python завезли async, почему-то maintainer'ы Django прое... момент, когда надо было бросать всё и завозить async в Django. Да я знаю, что async на уровне обработчиков появился в 3-й версии Django, но без async ORM, он нахер не нужен. Исключения, это проксирование запросов и когда можно достать данные из кеша и не ходить в БД, но очень маленький процент приложений.

Пока очевидный выбор это TortoiseORM, если хочется синтаксис Django и хочется быть быстрее SQLAlchemy (правда, не всегда).

Зарегистрируйтесь на Хабре, чтобы оставить комментарий