简体   繁体   中英

Django pagination: EmptyPage: That page contains no results

When using Django CBV ListView with pagination:

class Proposals(ListView):
    model = Proposal
    ordering = "id"
    paginate_by = 10

In the browser, if I provide a page that is out of range, I get an error:

在此处输入图像描述

I would like to have a different behaviour: to fallback to the last existing page if the provided page is out of range.

I dug into Django source code paginator.py file and was surprised to find some code that does exactly this:

    def get_page(self, number):
        """
        Return a valid page, even if the page argument isn't a number or isn't
        in range.
        """
        try:
            number = self.validate_number(number)
        except PageNotAnInteger:
            number = 1
        except EmptyPage:
            number = self.num_pages
        return self.page(number)

So using paginator.get_page(page) (and not paginator.page(page) ) would be the way to go. However, ListView does not use it.

What is the best way to deal with this?

Thanks.

The only solution I found is by overriding the paginate_queryset method. However I don't like it as I'm forced to rewrite the whole logic while I just want to change a single line.

Open to any better suggestion.

class PermissivePaginationListView(ListView):
    def paginate_queryset(self, queryset, page_size):
        """
        This is an exact copy of the original method, jut changing `page` to `get_page` method to prevent errors with out of range pages.
        This is useful with HTMX, when the last row of the table is deleted, as the current page in URL is not valid anymore because there is no result in it.
        """
        paginator = self.get_paginator(
            queryset,
            page_size,
            orphans=self.get_paginate_orphans(),
            allow_empty_first_page=self.get_allow_empty(),
        )
        page_kwarg = self.page_kwarg
        page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1
        try:
            page_number = int(page)
        except ValueError:
            if page == "last":
                page_number = paginator.num_pages
            else:
                raise Http404(_("Page is not “last”, nor can it be converted to an int."))
        try:
            page = paginator.get_page(page_number)
            return (paginator, page, page.object_list, page.has_other_pages())
        except InvalidPage as e:
            raise Http404(
                _("Invalid page (%(page_number)s): %(message)s")
                % {"page_number": page_number, "message": str(e)}
            )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM