Как сделать срез в Django ORM без all()?

Ситуация проста до безобразия. На страницу прилетает содержимое таблицы через пагинацию, но пагинация режет queryset уже после выполнения запроса к базе, а запрос выглядит так:
fooset = barmodel.objects.all().order_by('-foobar')

Поскольку в таблице порядка 10000000 строк, запрос идет некультурно долго. Как реализовать пагинацию на моменте запроса, без использования all(), что писать в фильтр?
Сейчас пагинация делается так:
current_page = Paginator(fooset,15)
page = request.GET.get('page')
try:
  context['foo'] = current_page.page(page)  
except PageNotAnInteger:
  context['foo'] = current_page.page(1)  
except EmptyPage:
  context['foo'] = current_page.page(current_page.num_pages)
  • Вопрос задан
  • 647 просмотров
Решения вопроса 2
@dimuska139
Backend developer
Если Вы считаете, что из базы в данном случае вытаскиваются все записи, а потом на уровне кода часть из них обрезается, то это не так. all() не делает запрос к базе. Запрос вместе с LIMIT выполняется уже внутри пагинатора.

Это я к тому, что, скорее всего, Вы увидели, что страница с пагинатором грузится безумно долго и предположили, что из базы выгребаются все записи, но это совсем не так. Долго это выполняется потому, что на таком количестве строк стандартные решения пагинации будут в принципе работать плохо, потому что на "дальних" страницах курсор базы данных будет перебирать все записи, идущие до этой страницы. Кроме того, пагинатор выполняет count-запрос, который выполняется долго, потому что это фулскан всей таблицы, где миллионы записей.
Ответ написан
Комментировать
sergey-gornostaev
@sergey-gornostaev Куратор тега Django
Седой и строгий
Во-первых, вам не нужен all, можно просто

fooset = barmodel.objects.order_by('-foobar')

Во-вторых, у класса QuerySet переопределена операция среза, так что fooset[:100] превратиться в select с limit 100.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы