Django 5 для начинающих

Прогресс по курсу:  9/1004

6.2 Добавление постраничной разбивки
2 из 3 шагов пройдено
0 из 5 баллов  получено

Обработка ошибок постраничной разбивки

Теперь, когда постраничная разбивка работает, в представление можно добавить обработку исключений, вызванных ошибками постраничной разбивки.

Параметр page, используемый представлением для извлечения заданной страницы, потенциально может применяться с неправильными значениями, такими как несуществующие номера страниц или строковое значение, которое нельзя использовать в качестве номера страницы. Мы выполним соответствующую обработку ошибок для таких случаев.

Пройдите по URL-адресу http://127.0.0.1:8000/blog/?page=3 в своем браузере.

Вы должны увидеть следующую ниже страницу с ошибкой:

При извлечении страницы 3 объект Paginator выдает исключение EmptyPage, поскольку она находится вне диапазона.
Подлежащих отображению результатов нет. Давайте обработаем эту ошибку в представлении.

Отредактируйте файл views.py приложения blog, добавив необходимую инструкцию импорта и видоизменив представление post_list, как показано ниже:

from django.shortcuts import render, get_object_or_404
from .models import Post
from django.core.paginator import Paginator, EmptyPage


def post_list(request):
    post_list = Post.published.all()
    # Постраничная разбивка с 3 постами на страницу
    paginator = Paginator(post_list, 3)
    page_number = request.GET.get('page', 1)
    try:
        posts = paginator.page(page_number)
    except EmptyPage:
        # Если page_number находится вне диапазона, то
        # выдать последнюю страницу
        posts = paginator.page(paginator.num_pages)
    return render(request,
                  'blog/post/list.html',
                  {'posts': posts})

Мы добавили блок try ... except, чтобы при извлечении страницы управлять исключением EmptyPage.

Если запрошенная страница находится вне диапазона, то мы возвращаем последнюю страницу результатов.

Мы получаем общее число страниц посредством paginator.num_pages. Общее число страниц совпадает с номером последней страницы.

Снова пройдите по URL-адресу http://127.0.0.1:8000/blog/?page=3 в своем браузере.

Теперь исключение управляется представлением, и последняя страница результатов возвращается, как показано ниже:

Данное представление также должно обрабатывать случай, когда в параметре page передается нечто отличное от целого числа.

Пройдите по URL-адресу http://127.0.0.1:8000/blog/?page=asdf в своем браузере.

Вы должны увидеть следующую ниже страницу ошибки:

 

В этом случае при извлечении страницы asdf объект Paginator выдает исключение PageNotAnInteger, поскольку номера страниц могут быть только целыми числами. Давайте обработаем эту ошибку в представлении.

Отредактируйте файл views.py приложения blog, добавив необходимую инструкцию импорта и видоизменив представление post_list, как показано ниже:

from django.shortcuts import render, get_object_or_404
from .models import Post
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger


def post_list(request):
    post_list = Post.published.all()
    # Постраничная разбивка с 3 постами на страницу
    paginator = Paginator(post_list, 3)
    page_number = request.GET.get('page')
    try:
        posts = paginator.page(page_number)
    except PageNotAnInteger:
        # Если page_number не целое число, то
        # выдать первую страницу
        posts = paginator.page(1)
    except EmptyPage:
        # Если page_number находится вне диапазона, то
        # выдать последнюю страницу результатов
        posts = paginator.page(paginator.num_pages)
    return render(request,
                  'blog/post/list.html',
                  {'posts': posts})

Мы добавили новый блок except, чтобы при извлечении страницы управлять исключением PageNotAnInteger.
Если запрошенная страница не является целым числом, то мы возвращаем первую страницу результатов.

Снова пройдите по URL-адресу http://127.0.0.1:8000/blog/?page=asdf в своем браузере.

Теперь исключение обрабатывается представлением, и первая страница результатов возвращается, как показано ниже на рисунке:

Теперь постраничная разбивка постов блога полностью реализована.

Подробнее о классе Paginator можно узнать на странице https://docs.djangoproject.com/en/5.0/ref/paginator/.


  • Комментария
Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий

А почему, вместо того, чтобы самому прописывать блоки try-except для того, чтобы поймать не существующие страницы, не прописать метод get_page, вместо page в этой строке "posts = paginator.page(page_number)". Он автоматом реализовывает данную логику.

@Кислинский_Роман, Да, все верно говорите, можно убрать логику try-except и заменить строку:

posts = paginator.page(page_number)

на следующую: 

posts = paginator.get_page(page_number)

И все будет работать также. Для этого мы и стараемся оставлять ссылки на документации, так как все варианты просто не возможно рассмотреть. А в данном примере мы просто хотели показать как обработать исключения в наших представлениях.

Изменен Илья Перминов

Будет ли дальше разбор пагинации не только по следующей и предыдущей странице, но и по адресным: 

<prev 1 2 3 4 5 next>?

Изменен Марат Асылбаев

@Марат_Асылбаев, Это делается совсем элементарно, переписыванием вывода в шаблоне:

<div class="pagination p-3">
    {% if page.has_previous %}
        <a class="page-link" href="?page={{ page.previous_page_number }}">Previous</a>
    {% endif %}
    {% for pages in page.paginator.page_range %}
        {% if page.number != pages %}
            <a class="page-link" href="?page={{ pages }}">{{ pages }}</a>
        {% else %}
            <a class="page-link disabled" href="?page={{ pages }}">{{ pages }}</a>
        {% endif %}
    {% endfor %}
    {% if page.has_next %}
        <a class="page-link" href="?page={{ page.next_page_number }}">Next</a>
    {% endif %}
</div>

Вот такой результат будет после добавления Bootstrap.

@Илья_Перминов, Спасибо!

@Илья_Перминов, а у меня отображение стремное, не понятно на какой странице сейчас

@Никита_Ильин, В коде который я скидывал используются стили Bootstrap, нужно или писать свои стили и подключать их. 

<div class="pagination p-3">
    {% if page.has_previous %}
        <a class="page-link" href="?page={{ page.previous_page_number }}">Previous</a>
    {% endif %}
    {% for pages in page.paginator.page_range %}
        {% if page.number != pages %}
            <a class="page-link" href="?page={{ pages }}">{{ pages }}</a>
        {% else %}
            {{ pages }} {# вот тут находится страница, на которой вы сейчас, можете оформлять по своему усмотрению #}
        {% endif %}
    {% endfor %}
    {% if page.has_next %}
        <a class="page-link" href="?page={{ page.next_page_number }}">Next</a>
    {% endif %}
</div>