diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py index c4a8cd3e05..b72173bd76 100644 --- a/django/views/generic/list_detail.py +++ b/django/views/generic/list_detail.py @@ -49,10 +49,17 @@ def object_list(request, queryset, paginate_by=None, page=None, if not page: page = request.GET.get('page', 1) try: - page = int(page) - object_list = paginator.get_page(page - 1) - except (InvalidPage, ValueError): - if page == 1 and allow_empty: + page_number = int(page) + except ValueError: + if page == 'last': + page_number = paginator.pages + else: + # Page is not 'last', nor can it be converted to an int + raise Http404 + try: + object_list = paginator.get_page(page_number - 1) + except InvalidPage: + if page_number == 1 and allow_empty: object_list = [] else: raise Http404 @@ -60,13 +67,13 @@ def object_list(request, queryset, paginate_by=None, page=None, '%s_list' % template_object_name: object_list, 'is_paginated': paginator.pages > 1, 'results_per_page': paginate_by, - 'has_next': paginator.has_next_page(page - 1), - 'has_previous': paginator.has_previous_page(page - 1), - 'page': page, - 'next': page + 1, - 'previous': page - 1, - 'last_on_page': paginator.last_on_page(page - 1), - 'first_on_page': paginator.first_on_page(page - 1), + 'has_next': paginator.has_next_page(page_number - 1), + 'has_previous': paginator.has_previous_page(page_number - 1), + 'page': page_number, + 'next': page_number + 1, + 'previous': page_number - 1, + 'last_on_page': paginator.last_on_page(page_number - 1), + 'first_on_page': paginator.first_on_page(page_number - 1), 'pages': paginator.pages, 'hits' : paginator.hits, 'page_range' : paginator.page_range diff --git a/docs/generic_views.txt b/docs/generic_views.txt index 96635f7d3f..33c39b7e12 100644 --- a/docs/generic_views.txt +++ b/docs/generic_views.txt @@ -688,9 +688,8 @@ A page representing a list of objects. * ``paginate_by``: An integer specifying how many objects should be displayed per page. If this is given, the view will paginate objects with ``paginate_by`` objects per page. The view will expect either a ``page`` - query string parameter (via ``GET``) containing a 1-based page - number, or a ``page`` variable specified in the URLconf. See - "Notes on pagination" below. + query string parameter (via ``GET``) or a ``page`` variable specified in + the URLconf. See "Notes on pagination" below. * ``template_name``: The full name of a template to use in rendering the page. This lets you override the default template name (see below). @@ -780,7 +779,7 @@ specify the page number in the URL in one of two ways: (r'^objects/page(?P[0-9]+)/$', 'object_list', dict(info_dict)) * Pass the page number via the ``page`` query-string parameter. For - example, a URL would look like this: + example, a URL would look like this:: /objects/?page=3 @@ -789,7 +788,16 @@ specify the page number in the URL in one of two ways: to create a link to every page of results. These values and lists are is 1-based, not 0-based, so the first page would be -represented as page ``1``. +represented as page ``1``. As a special case, you are also permitted to use +``last`` as a value for ``page``:: + + /objects/?page=last + +This allows you to access the final page of results without first having to +determine how many pages there are. + +Note that ``page`` *must* be either a valid page number or the value ``last``; +any other value for ``page`` will result in a 404 error. ``django.views.generic.list_detail.object_detail`` --------------------------------------------------