Evgenii Legotckoi
Evgenii Legotckoi08 січня 2018 р. 02:52

Django - Підручник 031. Змініть URL-адресу без перезавантаження сторінки з частковим завантаженням вмісту

Що менше інформації доводиться передавати сайту на кожен запит, то краще. Оскільки отримуємо менше навантаження на сервер і канал зв'язку. Першим таким покращенням на сайті я зробив підвантаження списку статей під час навігації по пагінатору сторінок.

Сенс у тому, що коли користувач хоче перейти на наступну сторінку зі списком статей і кликає на посилання в пагінаторі , то відбувається перехоплення події кліка, подія скасовується, але надсилається 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 .

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

B
  • 24 лютого 2020 р. 00:37

Евгений Здравствуйте! Не могу понять вот эту часть кода: url: jQuery(this).attr('action')
наверное здесь должен быть путь к url, тогда 'action' на какой url указывает?

Evgenii Legotckoi
  • 24 лютого 2020 р. 03:54

Добрый день. Там будет url, на который указывает ссылка тега a в пагинаторе, если правильно помню )) Написал этот код и забыл.

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 листопада 2024 р. 06:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject04 червня 2022 р. 03:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Слідкуйте за нами в соціальних мережах