Pull to refresh

Comments 15

Он тут не поможет. К тому же он тупее тупого.
Прямо сейчас в проекте:

FROM `socialaccount_socialaccount` WHERE `socialaccount_socialaccount`.`user_id` IN (40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40)
prefetch_related даст нехилую нагрузку на бд как по количеству запросов к бд так и по объему самих данных.
Работает он предельно просто: сначала выполняется основной запрос, а потом на уровне питон кода для всех RelatedObjects генерит новый запрос на выборку всех связанных объектов. В случае с моделью Page описанной в статье получается 5 запросов к бд. 1 на выборку самой Page и еще 4 на получение Translations для каждого переводимого поля. Теперь представим что в этих полям мы храним «оч.многобуквенные» данные для большого количества языков. Лично я бы предпочел множество запросов с меньшим объемом возвращаемых данных (может и зря)
page.filed.translations.filter(lng='ru').first()
upd: ошибочка вышла в локальном примере. будет 9 запросов. 1 основной, 4 на получение id переводов и 4 на получение самих переводов.
было: Page.objects.filter(id=1).prefetch_related('content', 'title', 'description', 'keywords').first()
стало: Page.objects.filter(id=1).prefetch_related('content__translations', 'title__translations', 'description__translations', 'keywords__translations').first(), что равносильно 1му варианту только без отложенной разгузки.
Боюсь Вы не правы. prefetch_related при не правильном использовании создаст только дополнительные проблемы. Когда мы говорим о фильтрации то он не кеширует запрос, который еще не был отфильтрован. Соответственно его нужно писать вместе с объектом Prefetch() и передавать в него уже отфильтрованный кверисет. это будет делать только 1 запрос в БД!
В общем-то, хорошее решение. Я про модель многоязычности :)
А сырой sql, на мой взгляд все равно лучше, хоть и менее DRY. Хранить его рядом с моделью и просить обновлять вместе с ней.
Ну не будете же вы каждую неделю переделывать таблицы? А if else в шесть слоев и map(lambda x) это уже что-то за гранью. ИМХО, конечно.
Дополню мысль: проще делать два запроса. Один для получения многоязычных полей и второй через орм (если понадобится), для получения всех остальных. Можно даже менеджер отдельный прикрутить.
Недостаток raw перед extra — у него отсутсвуют стандартные методы, например filter и get.
Это действительно так.
Но опять же, возвращаясь к модели: что там фильтровать?
И если это даже понадобится, лучше сделать дополнительный запрос с exists(). Т.е. я предлагаю использовать raw только чтобы стянуть переводы.
Навскидку — на странице вывести список дочерних страниц, причем title надо переводить.
Не вопрос:

children = parent.children.filter(is_active=True).order_by('order_field').values_list('id', flat=True)
pages = {x.id for x in Page.objects.extra(translations(where={'id': children}))}
ordered_pages = (pages[pk] for pk in children)

В def translations уже включить обработку where на свой вкус.
Кажется с ветки 1.6 поменялась сигнатура join. В ветке 1.5 не было параметра join_field, а в tuple connection передавалось 4 элемента
Да, сигнатура была изменена, но точно не скажу в какой версии.
Если вдруг кто-то все еще находит эту статью поиском по «Django left join», то могу сообщить, что это решение не работает уже как минимум для 1.8 версии. Сигнатура метода `join()` изменилась снова и теперь снова не принимает эти аргументы.
Sign up to leave a comment.

Articles