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
Дмитрий

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

  • Результат:60бали,
  • Рейтинг балів-1
Дмитрий

C++ - Тест 003. Условия и циклы

  • Результат:92бали,
  • Рейтинг балів8
d
  • dsfs
  • 26 квітня 2024 р. 14:56

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

  • Результат:80бали,
  • Рейтинг балів4
Останні коментарі
k
kmssr09 лютого 2024 р. 05:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 12:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 21:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 19:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 грудня 2023 р. 08:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
G
George1307 травня 2024 р. 10:27
добавить qlineseries в функции в функции: "GPlotter::addSeries(QString title, QVector &arr)" я вызываю метод setChart(...), я в конструктор передал адрес на QChartView элемент
BlinCT
BlinCT05 травня 2024 р. 15:46
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
PS
Peter Son04 травня 2024 р. 03:57
Best Indian Food Restaurant In Cincinnati OH Ready to embark on a gastronomic journey like no other? Join us at App india restaurant and discover why we're renowned as the Best Indian Food Restaurant In Cincinnati OH . Whether y…
Evgenii Legotckoi
Evgenii Legotckoi03 травня 2024 р. 00:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
IscanderChe
IscanderChe30 квітня 2024 р. 14:22
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…

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