Paginate without errors if a page doesn't exist

This commit is contained in:
Danielle McLean 2024-05-19 15:59:43 +10:00
parent 8d8aa4749b
commit d21d4bda83
Signed by: 00dani
GPG key ID: 6854781A0488421C
2 changed files with 29 additions and 32 deletions

View file

@ -1,35 +1,32 @@
from django.core.paginator import Paginator
from typing import Callable
from django.core.paginator import Page, Paginator
from django.shortcuts import redirect
from lemoncurry.middleware import ResponseException
def paginate(queryset, reverse, page):
class Page:
def __init__(self, i):
self.i = i
def paginate(queryset, reverse: Callable[[int], str], page: int | None) -> Page:
def redirect_to_page(i: int):
raise ResponseException(redirect(reverse(i)))
@property
def url(self):
return reverse(self.i)
@property
def current(self):
return self.i == entries.number
# If the first page was requested, redirect to the clean version of the URL
# with no page suffix.
if page == 1:
raise ResponseException(redirect(Page(1).url))
def reversible(p: Page) -> Page:
p.reverse = reverse
return p
paginator = Paginator(queryset, 10)
entries = paginator.page(page or 1)
entries.pages = tuple(Page(i) for i in paginator.page_range)
# If no page number was specified, return page one.
if page is None:
return reversible(paginator.page(1))
if entries.has_previous():
entries.prev = Page(entries.previous_page_number())
if entries.has_next():
entries.next = Page(entries.next_page_number())
# If the first page was explicitly requested, or the page number was negative, redirect to page one with no URL suffix.
if page <= 1:
redirect_to_page(1)
return entries
# If the page requested is larger than the last page, then redirect to the last page.
if page > paginator.num_pages:
redirect_to_page(paginator.num_pages)
# Just return the current page! Hooray!
return reversible(paginator.page(page))

View file

@ -110,29 +110,29 @@
<nav>
<ul class="pagination">
{% if entries.prev %}
{% if entries.has_previous() %}
<li class="page-item">
<a class="page-link" rel="prev" href="{{ entries.prev.url }}">
<a class="page-link" rel="prev" href="{{ entries.reverse(entries.previous_page_number()) }}">
<i class="fas fa-step-backward" aria-hidden="true"></i> <span class="sr-only">previous page</span>
</a>
</li>
{% endif %}
{% for page in entries.pages %}
{% if page.current %}
{% for i in entries.paginator.page_range %}
{% if i == entries.number %}
<li class="page-item active">
<span class="page-link">{{ page.i }} <span class="sr-only">(current page)</span></span>
<span class="page-link">{{ i }} <span class="sr-only">(current page)</span></span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="{{ page.url }}">{{ page.i }}</a>
<a class="page-link" href="{{ entries.reverse(i) }}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if entries.next %}
{% if entries.has_next() %}
<li class="page-item">
<a class="page-link" rel="next" href="{{ entries.next.url }}">
<a class="page-link" rel="next" href="{{ entries.reverse(entries.next_page_number()) }}">
<i class="fas fa-step-forward" aria-hidden="true"></i> <span class="sr-only">next page</span>
</a>
</li>