It's 2012 all up in here
[mediagoblin.git] / mediagoblin / tools / pagination.py
CommitLineData
03ae172a 1# GNU MediaGoblin -- federated, autonomous media hosting
cf29e8a8 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
03ae172a
AW
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import urllib
18import copy
19from math import ceil, floor
20from itertools import izip, count
21
ee91c2b8 22
03ae172a
AW
23PAGINATION_DEFAULT_PER_PAGE = 30
24
ee91c2b8 25
03ae172a
AW
26class Pagination(object):
27 """
28 Pagination class for mongodb queries.
29
30 Initialization through __init__(self, cursor, page=1, per_page=2),
31 get actual data slice through __call__().
32 """
33
34 def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE,
35 jump_to_id=False):
36 """
37 Initializes Pagination
38
39 Args:
40 - page: requested page
41 - per_page: number of objects per page
ee91c2b8
CAW
42 - cursor: db cursor
43 - jump_to_id: ObjectId, sets the page to the page containing the
44 object with _id == jump_to_id.
03ae172a
AW
45 """
46 self.page = page
47 self.per_page = per_page
48 self.cursor = cursor
49 self.total_count = self.cursor.count()
50 self.active_id = None
51
52 if jump_to_id:
53 cursor = copy.copy(self.cursor)
54
55 for (doc, increment) in izip(cursor, count(0)):
eabe6b67 56 if doc._id == jump_to_id:
03ae172a
AW
57 self.page = 1 + int(floor(increment / self.per_page))
58
59 self.active_id = jump_to_id
60 break
61
62
63 def __call__(self):
64 """
65 Returns slice of objects for the requested page
66 """
67 return self.cursor.skip(
68 (self.page - 1) * self.per_page).limit(self.per_page)
69
70 @property
71 def pages(self):
72 return int(ceil(self.total_count / float(self.per_page)))
73
74 @property
75 def has_prev(self):
76 return self.page > 1
77
78 @property
79 def has_next(self):
80 return self.page < self.pages
81
82 def iter_pages(self, left_edge=2, left_current=2,
83 right_current=5, right_edge=2):
84 last = 0
85 for num in xrange(1, self.pages + 1):
86 if num <= left_edge or \
87 (num > self.page - left_current - 1 and \
88 num < self.page + right_current) or \
89 num > self.pages - right_edge:
90 if last + 1 != num:
91 yield None
92 yield num
93 last = num
94
95 def get_page_url_explicit(self, base_url, get_params, page_no):
ee91c2b8 96 """
03ae172a 97 Get a page url by adding a page= parameter to the base url
ee91c2b8 98 """
03ae172a
AW
99 new_get_params = copy.copy(get_params or {})
100 new_get_params['page'] = page_no
101 return "%s?%s" % (
102 base_url, urllib.urlencode(new_get_params))
103
104 def get_page_url(self, request, page_no):
ee91c2b8 105 """
03ae172a
AW
106 Get a new page url based of the request, and the new page number.
107
108 This is a nice wrapper around get_page_url_explicit()
ee91c2b8 109 """
03ae172a 110 return self.get_page_url_explicit(
05788ef4 111 request.full_path, request.GET, page_no)