App Engine Python SDK version 1.9.13
[gae.git] / python / google / appengine / _internal / django / core / paginator.py
blob495cdf2d7644b1b7cac05b38b5b3bf2971d50893
1 from math import ceil
3 class InvalidPage(Exception):
4 pass
6 class PageNotAnInteger(InvalidPage):
7 pass
9 class EmptyPage(InvalidPage):
10 pass
12 class Paginator(object):
13 def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
14 self.object_list = object_list
15 self.per_page = per_page
16 self.orphans = orphans
17 self.allow_empty_first_page = allow_empty_first_page
18 self._num_pages = self._count = None
20 def validate_number(self, number):
21 "Validates the given 1-based page number."
22 try:
23 number = int(number)
24 except ValueError:
25 raise PageNotAnInteger('That page number is not an integer')
26 if number < 1:
27 raise EmptyPage('That page number is less than 1')
28 if number > self.num_pages:
29 if number == 1 and self.allow_empty_first_page:
30 pass
31 else:
32 raise EmptyPage('That page contains no results')
33 return number
35 def page(self, number):
36 "Returns a Page object for the given 1-based page number."
37 number = self.validate_number(number)
38 bottom = (number - 1) * self.per_page
39 top = bottom + self.per_page
40 if top + self.orphans >= self.count:
41 top = self.count
42 return Page(self.object_list[bottom:top], number, self)
44 def _get_count(self):
45 "Returns the total number of objects, across all pages."
46 if self._count is None:
47 try:
48 self._count = self.object_list.count()
49 except (AttributeError, TypeError):
50 # AttributeError if object_list has no count() method.
51 # TypeError if object_list.count() requires arguments
52 # (i.e. is of type list).
53 self._count = len(self.object_list)
54 return self._count
55 count = property(_get_count)
57 def _get_num_pages(self):
58 "Returns the total number of pages."
59 if self._num_pages is None:
60 if self.count == 0 and not self.allow_empty_first_page:
61 self._num_pages = 0
62 else:
63 hits = max(1, self.count - self.orphans)
64 self._num_pages = int(ceil(hits / float(self.per_page)))
65 return self._num_pages
66 num_pages = property(_get_num_pages)
68 def _get_page_range(self):
69 """
70 Returns a 1-based range of pages for iterating through within
71 a template for loop.
72 """
73 return range(1, self.num_pages + 1)
74 page_range = property(_get_page_range)
76 QuerySetPaginator = Paginator # For backwards-compatibility.
78 class Page(object):
79 def __init__(self, object_list, number, paginator):
80 self.object_list = object_list
81 self.number = number
82 self.paginator = paginator
84 def __repr__(self):
85 return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
87 def has_next(self):
88 return self.number < self.paginator.num_pages
90 def has_previous(self):
91 return self.number > 1
93 def has_other_pages(self):
94 return self.has_previous() or self.has_next()
96 def next_page_number(self):
97 return self.number + 1
99 def previous_page_number(self):
100 return self.number - 1
102 def start_index(self):
104 Returns the 1-based index of the first object on this page,
105 relative to total objects in the paginator.
107 # Special case, return zero if no items.
108 if self.paginator.count == 0:
109 return 0
110 return (self.paginator.per_page * (self.number - 1)) + 1
112 def end_index(self):
114 Returns the 1-based index of the last object on this page,
115 relative to total objects found (hits).
117 # Special case for the last page because there can be orphans.
118 if self.number == self.paginator.num_pages:
119 return self.paginator.count
120 return self.number * self.paginator.per_page