Предварительная выборка огромных наборов вопросов в django

TLDR: как предотвратить появление очень больших наборов IN в генерируемом SQL-запросе?

Когда я предварительно извлекаю поле ManyToMany, указывающее на модель Tag, из модели Object:

obj_qs = models.Object.objects.filter(created_time__gt = 2024)
obj_qs.prefetch_related('tags')

Я получаю предварительную выборку SQL-запроса следующего вида:

SELECT (`main_object_tag`.`object_id`) AS `_prefetch_related_val_object_id`, `main_tag`.`id`, `main_tag`.`name` FROM `main_tag` INNER JOIN `main_object_tag` ON (`main_tag`.`id` = `main_object_tag`.`tag_id`) WHERE `main_object_tag`.`object_id` IN (1, 2, 3, 4, 5); args=(1, 2, 3, 4, 5)

Проблема в том, что при таком подходе предложение IN может быть огромным - в моем случае сотни тысяч объектов. Можно ли это как-то обойти - использовать запрос вместо спецификации «IN»?

Экстра: почему?

Впоследствии мы будем сериализовать объекты следующим образом:

return JsonResponse([
  {
    'name': obj.name,
    'tags': [tag.name for tag in obj.tags.all()]
  } for obj in obj_qs
])

Если сумма слишком велика, можно работать с chunks, и таким образом получать набор запросов кусками по ~10'000 элементов, например.

Вы можете использовать .iterator(…) [Django-doc] для этого:

return JsonResponse(
    [
        {'name': obj.name, 'tags': [tag.name for tag in obj.tags.all()]}
        for obj in obj_qs.iterator(10000)
    ]
)

Другая идея - ограничить объем передаваемых данных, извлекая только соответствующие данные из объекта и тега, в данном случае .name, используя .only(…) [Django-doc]:

from django.db.models import Prefetch

obj_qs = models.Object.objects.filter(created_time__gt=2024).only('name')
obj_qs.prefetch_related(Prefetch('tags', Tag.objects.only('pk', 'name')))
Вернуться на верх