Django : Paginator page exceed max page

Viewed 306

I'm currently working on CBV Paginator in Django redirecting last page when given page exceed maximum pages. So, let's say there's Post models that has 200 instances and ListView with paginated_by=10. Then maximum page is 20.

So, when I enter URL with "?page=21", it return 404 Error Page. I want to redirect to maximum page.

How can I do?

1 Answers

If you take a look at django.views.generic.listlink you have the following ListView class:

class ListView(MultipleObjectTemplateResponseMixin, BaseListView):
    """
    Render some list of objects, set by `self.model` or `self.queryset`.
    `self.queryset` can actually be any iterable of items, not just a queryset.
    """

which include BaseListView for pagination which inherit from MultipleObjectMixin:

class MultipleObjectMixin(ContextMixin):
    """A mixin for views manipulating multiple objects."""
    ... #other functions
    def paginate_queryset(self, queryset, page_size):
    """Paginate the queryset, if needed."""
    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.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 404 page you want to redirect

You need to override the InvalidPage exception handling which raise the Http404:

from django.views.generic.list import ListView

class YourListView(ListView):

    def paginate_queryset(self, queryset, page_size):
       """Paginate the queryset, if needed."""
       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.page(page_number)
           return (paginator, page, page.object_list, page.has_other_pages())
       except InvalidPage as e:
           page_number = paginator.num_pages #<-last page
           page = paginator.page(page_number)
           return (paginator, page, page.object_list, page.has_other_pages()) #<-return last page

Note: you can also use this custom class for other ListView

Related