2

Django gives me 404 error when the page number is invalid (ex. localhost/?page=9999).

But I want to redirect it the the first page. In function-based views, this can be done by catching InvalidPage exception.

Does anyone know how to do it in class-based views.

Thanks in advance.

Tianissimo
  • 1,240
  • 1
  • 11
  • 16

5 Answers5

1

Neither of the previous answers solved the problem for me. Maybe they did at one time. Here's how I did using django 1.3.1:

def get(self, *args, **kwargs):
    request = self.request
    try:
        return super(MyListView, self).get(*args, **kwargs)
    except Http404:
        if request.GET.get('page', 1) == 1:
            raise
    page1 = request.GET.copy()
    del page1['page']
    return redirect('%s?%s' % (request.path, page1.urlencode()))

I do a redirect, because I don't want people thinking the url is valid - there isn't a page N and we want to properly reflect that we are sending them back to page 1.

Julian
  • 2,814
  • 21
  • 31
0

Just override get_context_data method in your ListView class. It works great in my project. Just use code from @Coc B.

Of course remember to replace MyListView to your class name.

Griffi
  • 243
  • 2
  • 9
0

This worked for me, override paginate_queryset:

class MyListView(ListView):
    def paginate_queryset(self, queryset, page_size):
        try:
            return super(MyListView, self).paginate_queryset(queryset, page_size)
        except Http404:
            self.kwargs['page'] = 1  # return page 1 instead
            return super(MyListView, self).paginate_queryset(queryset, page_size)
azuer88
  • 73
  • 8
0

Call get_context_data and catch Http404 rather than InvalidPage.
Then assign the page value to 1, and recall get_context_data.

class MyListView(ListView):
    def get_context_data(self, **kwargs):
        try:
            return super(MyListView, self).get_context_data(**kwargs)
        except Http404:
            self.kwargs['page'] = 1
            return super(MyListView, self).get_context_data(**kwargs)

More info:

https://code.djangoproject.com/browser/django/trunk/django/views/generic/list.py#L33

https://code.djangoproject.com/browser/django/trunk/django/views/generic/list.py#L84

Coc B.
  • 665
  • 8
  • 10
-1

Override get_paginator in your class and run your checks there. Then override dispatch to redirect or return the normal view:

class MyListView(ListView):
    ...
    def get_paginator(self, queryset, per_page, orphans=0, allow_empty_first_page=True):
        paginator = super(MyListView, self).get_paginator(queryset, per_page, orphans=orphans, allow_empty_first_page=allow_empty_first_page)
        try:
            paginator.page(self.kwargs.get('page', 1))
        except EmptyPage: # or InvalidPage, but that's less precise
            self.is_empty = True

        return paginator

    def dispatch(self, request, *args, **kwargs):
        response = super(MyListView, self).dispatch(request, *args, **kwargs)
        if getattr(self, 'is_empty', False):
            return HttpResponseRedirect('/some/other/url/')
        else:
            return response
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thanks for your answer. Can paginator.page() be called with no arguments? – Tianissimo Jan 17 '12 at 15:34
  • Sorry, no, I've updated the answer above. I also noticed another problem in my dispatch method. That has been correct now too. – Chris Pratt Jan 17 '12 at 15:38
  • 1
    Hi, I've tried your code and it didn't work. I found 2 problems: 1) It seems that super().dispatch() immediately return a response without being kept in the variable so the line if getattr(...) line won't be called. 2) The get_paginator method is called after dispatch method. – Tianissimo Jan 18 '12 at 16:39