Що менше інформації доводиться передавати сайту на кожен запит, то краще. Оскільки отримуємо менше навантаження на сервер і канал зв'язку. Першим таким покращенням на сайті я зробив підвантаження списку статей під час навігації по пагінатору сторінок.
Сенс у тому, що коли користувач хоче перейти на наступну сторінку зі списком статей і кликає на посилання в пагінаторі , то відбувається перехоплення події кліка, подія скасовується, але надсилається AJAX запит на сервер з номером сторінки, що запитується. Коли сервер отримує такий запит, він робить рендеринг лише списку статей і надсилає його назад.
Заміна URL у браузері без перезавантаження сторінки
Для головної сторінки сайту я створив JavaScript файл index.js, у якому буде логіка AJAX запиту, а також прив'язка обробника кліку за посиланнями в пагінаторі. Важливим моментом є те, що я використовую для пагінатора django-bootstrap3 . Щоб підключити обробник кліка, я використовую селектор '.paginator > li > a' .
Вміст файлу буде наступним
class Index { static initPaginator() { document.body.querySelectorAll('.pagination > li > a') .forEach( link => link.addEventListener('click', Index.pagination_link_clickHandler) ); } static pagination_link_clickHandler(event){ event.preventDefault(); // запрещаем событие let path = event.target.href; // забираем путь let page = Global.getURLParameter(path, 'page'); if (typeof page !== 'undefined') { jQuery.ajax({ url: jQuery(this).attr('action'), type: 'POST', data: {'page': getURLParameter(path, 'page')}, // забираем номер страницы, которую нужно отобразить success : function (json) { // Если запрос прошёл успешно и сайт вернул результат if (json.result) { window.history.pushState({route: path}, "EVILEG", path); // устанавливаем URL в строку браузера jQuery("#articles-list").replaceWith(articles); // Заменяем div со списком статей на новый Index.initPaginator(); // Переинициализируем пагинатор jQuery(window).scrollTop(0); // Скроллим страницу в начало } } }); } } } Index.initPaginator();
Я намагаюся використовувати стандарт ecmascript 6. Тому для сторінки index використовується клас Index для узагальнення методів, що застосовуються.
Для отримання номера сторінки в URL використовуємо функцію getURLParameter .
Структура шаблонів
Таким чином, у нас має бути спеціальна структура шаблонів, а саме, має бути шаблон для рендерингу списку статей, у моєму випадку шаблон з попередньою статтею, а також шаблон головної сторінки сайту.
Тобто буде:
- article_preview.html - цей шаблон розглядати не будемо, оскільки він не цікавий для нас у цьому випадку
- article_previews_list.html
- index.html
index.html
index.html успадкований від базового шаблону base.html , в якому є блок для підключення javascript файлів.
{% extends 'base.html' %} {% block page %} {% include 'article_previews_list.html' %} {% endblock %} {% block javascript_footer %} <script src="/static/js/index.js"></script> {% endblock %}
article_previews_list.html
Список статей є div , який замінюватиметься при кожному запиті.
<div id="articles-list"> {% load bootstrap_pagination from bootstrap3 %} {% for article in object_list %} {% include 'knowledge/article_preview.html' %} {% endfor %} {% bootstrap_pagination object_list pages_to_show="10" %} </div>
urls.py
Маршрут для головної сторінки буде виглядати так
urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index') ]
views.py
А тепер розглянемо уявлення, яке повертатиме список статей або одразу всю сторінку
class IndexView(View): template_name = 'index.html' def get(self, request): return render(request=request, template_name=self.template_name, context={'object_list': get_paginated_page(request, Article.objects.all())}) def post(self, request): if request.is_ajax(): return JsonResponse({ "result": True, "articles": render_to_string( request=request, template_name='article_previews_list.html', context={'object_list': get_paginated_page(request, Article.objects.all())} ) }) else: raise Http404()
Важливим моментом є те, що сайт повинен коректно обробляти обидва види запитів як звичайний, так і AJAX запит. Оскільки користувач може зайти безпосередньо на одну зі сторінок, так і за допомогою пагінації на сайті.
Можливо, вас в даному коді зацікавить метод get_paginated_page, який за допомогою класу Paginator генерує потрібну сторінку для відображення.
# -*- coding: utf-8 -*- from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage def get_paginated_page(request, objects, number=10): current_page = Paginator(objects, number) page = request.GET.get('page') if request.method == 'GET' else request.POST.get('page') try: return current_page.page(page) except PageNotAnInteger: return current_page.page(1) except EmptyPage: return current_page.page(current_page.num_pages)
Для Django рекомендую VDS-сервера хостера Timeweb .
Евгений Здравствуйте! Не могу понять вот эту часть кода: url: jQuery(this).attr('action')
наверное здесь должен быть путь к url, тогда 'action' на какой url указывает?
Добрый день. Там будет url, на который указывает ссылка тега a в пагинаторе, если правильно помню )) Написал этот код и забыл.