Оптимизация пагинации django
Имеется сайт с довольно большой базой данных, более 40000 записей. При пагинации каждый раз выполняется запрос в бд, который занимает 1.5 секунды, что довольно долго, как для сайта. Пробовал кэширование view, но при переходе на следующую страницу пагинации кэш не срабатывает и запрос выполняется заново(после кэширования этой страницы, заново запрос не отправляется). Как возможно оптимизировать пагинацию, что бы снизить нагрузку на бд и сервер, а также ускорить время обработки запроса? Код view прилагаю.
class PostsView(View):
def get(self, request):
mobile = request.user_agent.is_mobile
time_now = timezone.now()
posts_all = Post.objects.all()
premium_posts = posts_all.filter(moderated=True, premium_till__gte=time_now)
normal_posts = posts_all.filter(Q(moderated=True, premium_till__lt=time_now) | Q(moderated=True, premium_till=None))
posts = list(chain(premium_posts, normal_posts))
page = request.GET.get('page')
paginator = Paginator(posts, 20)
if page is None:
difference = paginator.num_pages - 1
else:
difference = paginator.num_pages - int(page)
try:
posts_list = paginator.page(page)
except PageNotAnInteger:
posts_list = paginator.page(1)
except EmptyPage:
posts_list = paginator.page(paginator.num_pages)
return render(request, "blog_app/posts_list.html", {"posts_list": posts_list, "difference" : difference, "time_now" : time_now, "mobile" : mobile})
Ответы (2 шт):
Добавьте индексы в модель на все поля, используемые в фильтре и сортировке
Если используются связанные объекты - добавьте
select_related/prefetch_relatedЕсли используется сложная сортировка - подумайте о предсортировке (добавьте поле в модель, в котором будет храниться порядковый номер для типа сортировки и сортируйте по нему)
Если все плохо, то остается кеширование объектов через
django.core.cache.cacheи ждать еще ответов
А вообще добавьте django-debug-toolbar и посмотрите, какие запросы выполняются, кол-во дублей и время выполнения. Тогда можно будет проще понять в какую сторону идти
UPD: Кешировать можно раз в день или реже, в management_command.
Может быть, имеет смысл пагинировать на уровне SQL запроса? Когда делается Post.objects.all() ведь выгребается всё в буфер. Вроде, у ORM django есть вариант сразу в этом запросе задавать offset и limit. Нечто вида Post.objects.all()[1:50]