pagenumber.py
10.2 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# from typing import Sequence
# import warnings
# import six
# from math import ceil
# from collections import OrderedDict
# from sqlalchemy.orm.query import Query
# from pyramid.exceptions import HTTPNotFound
# from pyramid.response import Response
# from pyramid_restful.settings import api_settings
# from pyramid_restful.pagination.utilities import remove_query_param, replace_query_param
# from pyramid_restful.pagination.base import BasePagination
# __all__ = ['PageNumberPagination']
# def _positive_int(integer_string, strict=False, cutoff=None):
# """
# Cast a string to a strictly positive integer.
# """
# ret = int(integer_string)
# if ret < 0 or (ret == 0 and strict):
# raise ValueError()
# if cutoff:
# ret = min(ret, cutoff)
# return ret
# class InvalidPage(Exception):
# pass
# class PageNotAnInteger(InvalidPage):
# pass
# class EmptyPage(InvalidPage):
# pass
# class UnorderedObjectListWarning(RuntimeWarning):
# pass
# class Paginator:
# def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
# self.object_list = object_list
# self._check_object_list_is_ordered()
# self.per_page = int(per_page)
# self.orphans = int(orphans)
# self.allow_empty_first_page = allow_empty_first_page
# def validate_number(self, number):
# """
# Validates the given 1-based page number.
# """
# try:
# number = int(number)
# except (TypeError, ValueError):
# raise PageNotAnInteger('That page number is not an integer')
# if number < 1:
# raise EmptyPage('That page number is less than 1')
# if number > self.num_pages:
# if number == 1 and self.allow_empty_first_page:
# pass
# else:
# raise EmptyPage('That page contains no results')
# return number
# def page(self, number):
# """
# Returns a Page object for the given 1-based page number.
# """
# number = self.validate_number(number)
# bottom = (number - 1) * self.per_page
# top = bottom + self.per_page
# if top + self.orphans >= self.count:
# top = self.count
# return self._get_page(self.object_list[bottom:top], number, self)
# def _get_page(self, *args, **kwargs):
# """
# Returns an instance of a single page.
# This hook can be used by subclasses to use an alternative to the
# standard :cls:`Page` object.
# """
# return Page(*args, **kwargs)
# @property
# def count(self):
# """
# Returns the total number of objects, across all pages.
# """
# try:
# return self.object_list.count()
# except (AttributeError, TypeError):
# # AttributeError if object_list has no count() method.
# # TypeError if object_list.count() requires arguments
# # (i.e. is of type list).
# return len(self.object_list)
# @property
# def num_pages(self):
# """
# Returns the total number of pages.
# """
# if self.count == 0 and not self.allow_empty_first_page:
# return 0
# hits = max(1, self.count - self.orphans)
# return int(ceil(hits / float(self.per_page)))
# @property
# def page_range(self):
# """
# Returns a 1-based range of pages for iterating through within
# a template for loop.
# """
# return range(1, self.num_pages + 1)
# def _check_object_list_is_ordered(self):
# """
# Warn if self.object_list is unordered (typically a QuerySet).
# """
# if hasattr(self.object_list, 'ordered') and not self.object_list.ordered:
# warnings.warn(
# 'Pagination may yield inconsistent results with an unordered '
# 'object_list: {!r}'.format(self.object_list),
# UnorderedObjectListWarning
# )
# class Page(Sequence):
# def __init__(self, object_list, number, paginator):
# self.object_list = object_list
# self.number = number
# self.paginator = paginator
# def __repr__(self):
# return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
# def __len__(self):
# return len(self.object_list)
# def __getitem__(self, index):
# if not isinstance(index, (int, slice)):
# raise TypeError
# # The object_list is converted to a list so that if it was a QuerySet
# # it won't be a database hit per __getitem__.
# if not isinstance(self.object_list, list):
# self.object_list = list(self.object_list)
# return self.object_list[index]
# def has_next(self):
# return self.number < self.paginator.num_pages
# def has_previous(self):
# return self.number > 1
# def has_other_pages(self):
# return self.has_previous() or self.has_next()
# def next_page_number(self):
# return self.paginator.validate_number(self.number + 1)
# def previous_page_number(self):
# return self.paginator.validate_number(self.number - 1)
# def start_index(self):
# """
# Returns the 1-based index of the first object on this page,
# relative to total objects in the paginator.
# """
# # Special case, return zero if no items.
# if self.paginator.count == 0:
# return 0
# return (self.paginator.per_page * (self.number - 1)) + 1
# def end_index(self):
# """
# Returns the 1-based index of the last object on this page,
# relative to total objects found (hits).
# """
# # Special case for the last page because there can be orphans.
# if self.number == self.paginator.num_pages:
# return self.paginator.count
# return self.number * self.paginator.per_page
# class PageNumberPagination(BasePagination):
# """
# A simple page number based style that supports page numbers as query parameters.
# For example::
# http://api.example.org/accounts/?page=4
# http://api.example.org/accounts/?page=4&page_size=100
# page_size can be overridden as class attribute::
# class MyPager(PageNumberPagination):
# page_size = 10
# The resulting response JSON has four attributes, count, next, previous and results. Count indicates the
# total number of objects before pagination. Next and previous contain URLs that can be used to retrieve the next
# and previous pages of date respectively. The results attribute contains the list of objects that belong to page
# of data.
# Example::
# {
# 'count': 50,
# 'next': 'app.myapp.com/api/users?page=3',
# 'previous': 'app.myapp.com/api/users?page=1',
# 'results': [
# {id: 4, 'email': 'user4@myapp.com', 'name': 'John Doe'},
# {id: 5, 'email': 'user5@myapp.com', 'name': 'Jan Doe'}
# ]
# }
# """
# page_size = api_settings.page_size
# paginator_class = Paginator
# # Client can control the page using this query parameter.
# page_query_param = 'page'
# # Client can control the page size using this query parameter.
# # Default is 'None'. Set to eg 'page_size' to enable usage.
# page_size_query_param = None
# # Set to an integer to limit the maximum page size the client may request.
# # Only relevant if 'page_size_query_param' has also been set.
# max_page_size = None
# last_page_strings = ('last',)
# invalid_page_message = 'Invalid page "{page_number}": {message}.'
# def paginate_query(self, query, request):
# self.request = request
# # Force the execution of the query, so we don't make unnecessary db calls
# data = query.all() if isinstance(query, Query) else query
# page_size = self.get_page_size(request)
# if not page_size:
# return None
# page_number = request.params.get(self.page_query_param, 1)
# paginator = self.paginator_class(data, page_size)
# if page_number in self.last_page_strings:
# page_number = paginator.num_pages
# try:
# self.page = paginator.page(page_number)
# except InvalidPage as exc:
# msg = self.invalid_page_message.format(
# page_number=page_number, message=six.text_type(exc)
# )
# raise HTTPNotFound(msg)
# return list(self.page)
# def get_paginated_response(self, data):
# return Response(json=OrderedDict([
# ('count', self.page.paginator.count),
# ('next', self.get_next_link()),
# ('previous', self.get_previous_link()),
# ('results', data)
# ]))
# def get_page_size(self, request):
# if self.page_size_query_param:
# try:
# return _positive_int(
# request.params[self.page_size_query_param],
# strict=True,
# cutoff=self.max_page_size
# )
# except (KeyError, ValueError):
# pass
# return self.page_size
# def get_next_link(self):
# if not self.page.has_next():
# return None
# url = self.get_url_root()
# page_number = self.page.next_page_number()
# return replace_query_param(url, self.page_query_param, page_number)
# def get_previous_link(self):
# if not self.page.has_previous():
# return None
# url = self.get_url_root()
# page_number = self.page.previous_page_number()
# if page_number == 1:
# return remove_query_param(url, self.page_query_param)
# return replace_query_param(url, self.page_query_param, page_number)
# def get_url_root(self):
# """
# Override this if you need a different root url.
# For example if the app is behind a reverse proxy and you
# want to use the original host in the X-Forwarded-Host header.
# """
# return self.request.current_route_url()