Login

Extended Paginator

Author:
davisp
Posted:
August 27, 2007
Language:
Python
Version:
.96
Tags:
pagination paginator paging pager
Score:
1 (after 3 ratings)

Generate a list of page links like:

First Prev 1 2 3 4 5 6 7 Next Last

To use:

  1. Put Paginator.py into your app directory
  2. Copy pagination.html to your templates directory
  3. pass a paginator object to your Context
  4. include the pagination.html template on the page you wanted paginated

Feel free to send ideas for improvement. If enough people ask, I'll package this as a single app and perhaps even make the template inclusion into a templatetag for even easier use.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
-- Paginator.py

# BetterPaginator by spankalee
# Orignal from: http://www.djangosnippets.org/snippets/219/
# Downloaded: 08/22/2007 - davisp@neb.com

from django.core.paginator import ObjectPaginator, InvalidPage
from django.http import Http404

class Paginator(ObjectPaginator):
	def __init__(self, request=None, query_set=None, current_page=1, page_size=20, padding=3 ):
		from re import sub
		ObjectPaginator.__init__(self, query_set, page_size)
		if request is None or query_set is None:
			raise Http404
		self.path = sub( r'page/\d+/?$', '', request.path )
		self.path = sub( r'/$', '', self.path )
		self.query_str = '?' + request.GET.urlencode()
		if self.query_str == '?':
			self.query_str = ''
		self.current_page = int( current_page )
		self.page_size = page_size
		start = self.current_page-1 - padding
		end = self.current_page-1 + padding
		if start < 0:
			end += 0 - start
			start = 0
			if end >= self.pages:
				end = self.pages-1
		if end >= self.pages:
			start -= end - self.pages + 1
			end = self.pages-1
			if start < 0:
				start = 0
		self.first = start+1
		self.last = end+1
		self.page_numbers = [ { 'page': (p+1), 'url': self.path + '/page/' + str(p+1) + '/' + self.query_str } \
								for p in range( start, end+1 ) ]
		self.first_url = self.path + '/page/1/' + self.query_str
		self.prev_enabled = int( current_page ) > int( self.first )
		self.prev_url = self.path + '/page/' + str( self.current_page - 1 ) + '/' + self.query_str
		self.next_enabled = int( current_page ) < int( self.last )
		self.next_url = self.path + '/page/' + str( self.current_page + 1 ) + '/' + self.query_str
		self.last_url = self.path + '/page/' + str( self.pages ) + '/' + self.query_str
		self.is_paginated = self.pages > 1

	def get_page(self, page_num=None):
		try:
			if page_num is None:
				return ObjectPaginator.get_page(self, self.current_page-1)
			else:
				return ObjectPaginator.get_page(self, page_num)
		except InvalidPage:
			raise Http404

-- pagination.html

{% if paginator.is_paginated %}
	{% ifnotequal paginator.current_page 1 %}
		<a class="pagination" href="{{ paginator.first_url }}">First</a>
	{% else %}
		<span class="pagination disabled">First</a>
	{% endifnotequal %}

	{% if paginator.prev_enabled %}
		<a class="pagination" href="{{ paginator.prev_url }}">Previous</a>
	{% else %}
		<span class="pagination disabled">Previous</a>
	{% endif %}

	{% for p in paginator.page_numbers %}
		{% ifequal paginator.current_page p.page %}
			<span class="pagination current">{{ p.page }}</span>
		{% else %}
			<a href="{{ p.url }}">{{ p.page }}</a>
		{% endifequal %}
	{% endfor %}

	of {{ paginator.pages }}

	{% if paginator.next_enabled %}
		<a class="pagination" href="{{ paginator.next_url }}">Next</a>
	{% else %}
		<span class="pagination disabled">Next</a>
	{% endif %}

	{% ifnotequal paginator.current_page paginator.pages %}
		<a class="pagination" href="{{ paginator.last_url }}">Last</a>
	{% else %}
		<span class="pagination disabled">Last</a>
	{% endifnotequal %}

	<br>
{% endif %}
Matched: {{ paginator.hits }}

-- urls.py

	url( r'^$', 'eureka.root.views.results_list' ),
	url( r'^page/(?P<page>\d+)/$', 'eureka.root.views.results_list' ),

-- views.py

from eureka.root.paginator import Paginator, InvalidPage

def results_list( request, object_id=None, page=1 ):
        res = MyModel.objects.all() #Or similar
        #...
	paginator = Paginator( request, res, page )
	return render( request, 'root/result_list.html', {
			'search': search,
			'seq': col == 'seq',
			'lib': lib,
			'has_lib': lib is not None,
			'paginator': paginator, 
			'object_list': paginator.get_page()
		} )

More like this

  1. Paginator TemplateTag by trbs 7 years, 4 months ago
  2. Admin App/Model Custom Ordering by stephen_mcd 5 years, 5 months ago
  3. Template tag to create mailto links with options by celopes 6 years, 1 month ago
  4. 3rd Party App Directories by thalin 7 years, 1 month ago
  5. Twin column model admin index by richardbolt 7 years, 4 months ago

Comments

msoulier (on September 30, 2007):

I found that in the get_page method of the Paginator class, I had to change your else clause to

        else:
            return ObjectPaginator.get_page(self, page_num-1)

Note the -1. The ObjectPaginator counts from 0 and you count from 1, so I found that they were off by one otherwise.

Beyond that, it seems to work well. Thanks.

#

Please login first before commenting.