Чем меньше информации приходится передавать сайту на каждый запрос, тем лучше. Поскольку получаем меньшую нагрузку на сервер и на канал связи. Первым таким улучшением на сайте я сделал подгрузку списка статей при навигации по пагинатору страниц.
Смысл в том, что когда пользователь хочет перейти на следующую страницу со списком статей и кликает на ссылку в пагинаторе , то производится перехват события клика, событие отменяется, но высылается 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 в пагинаторе, если правильно помню )) Написал этот код и забыл.