Login

Extended Paginator

Author:
davisp
Posted:
August 27, 2007
Language:
Python
Version:
.96
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 - [email protected]

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. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 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.