mirror of https://github.com/sgoudham/Enso-Bot.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
4.7 KiB
Python
153 lines
4.7 KiB
Python
5 years ago
|
"""
|
||
|
Paginator
|
||
|
"""
|
||
|
|
||
|
from math import ceil
|
||
|
from six import string_types
|
||
|
from six.moves import range
|
||
|
|
||
|
class Paginator(object):
|
||
|
PER_PAGE = 10
|
||
|
total_pages = 0
|
||
|
total_items = 0
|
||
|
callback = None
|
||
|
|
||
|
def __init__(self, query, page=1, per_page=PER_PAGE, total=None,
|
||
|
padding=0, callback=None, static_query=False,
|
||
|
left_edge=2, left_current=3, right_current=4, right_edge=2):
|
||
|
"""
|
||
|
:param query: Iterable to paginate. Can be a query object, list or any iterables
|
||
|
:param page: current page
|
||
|
:param per_page: max number of items per page
|
||
|
:param total: Max number of items. If not provided, it will use the query to count
|
||
|
:param padding: Number of elements of the next page to show
|
||
|
:param callback: a function to callback on each item being iterated.
|
||
|
:param static_query: bool - When True it will return the query as is, without slicing/limit. Usally when using the paginator to just create the pagination.
|
||
|
# To customize the pagination
|
||
|
:param left_edge:
|
||
|
:param left_current:
|
||
|
:param right_current:
|
||
|
:param right_edge:
|
||
|
"""
|
||
|
|
||
|
self.query = query
|
||
|
self.callback = callback
|
||
|
self.static_query = static_query
|
||
|
self.left_edge = left_edge
|
||
|
self.left_current = left_current
|
||
|
self.right_edge = right_edge
|
||
|
self.right_current = right_current
|
||
|
|
||
|
if not isinstance(per_page, int) or per_page < 1:
|
||
|
raise TypeError('`per_page` must be a positive integer')
|
||
|
self.per_page = per_page
|
||
|
|
||
|
if not total:
|
||
|
try:
|
||
|
total = query.count()
|
||
|
except (TypeError, AttributeError):
|
||
|
total = len(query)
|
||
|
self.total_items = total
|
||
|
|
||
|
if page == "last":
|
||
|
page == self.total_pages
|
||
|
elif page == "first":
|
||
|
page = 1
|
||
|
self.page = self._sanitize_page_number(page)
|
||
|
|
||
|
self.padding = padding
|
||
|
|
||
|
def _sanitize_page_number(self, page):
|
||
|
if page == 'last':
|
||
|
return page
|
||
|
if isinstance(page, string_types) and page.isdigit():
|
||
|
page = int(page)
|
||
|
if isinstance(page, int) and (page > 0):
|
||
|
return page
|
||
|
return 1
|
||
|
|
||
|
@property
|
||
|
def total_pages(self):
|
||
|
"""The total number of pages."""
|
||
|
return int(ceil(self.total_items / float(self.per_page)))
|
||
|
|
||
|
@property
|
||
|
def has_prev(self):
|
||
|
"""True if a previous page exists."""
|
||
|
return self.page > 1
|
||
|
|
||
|
@property
|
||
|
def has_next(self):
|
||
|
"""True if a next page exists."""
|
||
|
return self.page < self.total_pages
|
||
|
|
||
|
@property
|
||
|
def next_page_number(self):
|
||
|
"""Number of the next page."""
|
||
|
return self.page + 1
|
||
|
|
||
|
@property
|
||
|
def prev_page_number(self):
|
||
|
"""Number of the previous page."""
|
||
|
return self.page - 1
|
||
|
|
||
|
@property
|
||
|
def pages_range(self):
|
||
|
start = (self.page - 1) * self.per_page
|
||
|
end = start + self.per_page - 1
|
||
|
return start, min(end, self.total_items - 1)
|
||
|
|
||
|
@property
|
||
|
def items(self):
|
||
|
if self.static_query:
|
||
|
return self.query
|
||
|
|
||
|
offset = (self.page - 1) * self.per_page
|
||
|
offset = max(offset - self.padding, 0)
|
||
|
limit = self.per_page + self.padding
|
||
|
if self.page > 1:
|
||
|
limit = limit + self.padding
|
||
|
|
||
|
if hasattr(self.query, 'limit') and hasattr(self.query, 'offset'):
|
||
|
return self.query.limit(limit).offset(offset)
|
||
|
elif isinstance(self.query, list):
|
||
|
return self.query[offset:offset + limit]
|
||
|
else:
|
||
|
return self.query
|
||
|
|
||
|
def __iter__(self):
|
||
|
for i in self.items:
|
||
|
yield self.callback(i) if self.callback else i
|
||
|
|
||
|
def __len__(self):
|
||
|
return self.total_pages
|
||
|
|
||
|
@property
|
||
|
def pages(self):
|
||
|
"""Iterates over the page numbers in the pagination."""
|
||
|
return self.iter_pages()
|
||
|
|
||
|
def iter_pages(self, left_edge=None, left_current=None, right_current=None, right_edge=None):
|
||
|
left_edge = left_edge or self.left_edge
|
||
|
left_current = left_current or self.left_current
|
||
|
right_edge = right_edge or self.right_edge
|
||
|
right_current = right_current or self.right_current
|
||
|
|
||
|
last = 0
|
||
|
for num in range(1, self.total_pages + 1):
|
||
|
is_active_page = (
|
||
|
num <= left_edge
|
||
|
or (
|
||
|
(num >= self.page - left_current) and
|
||
|
(num < self.page + right_current)
|
||
|
)
|
||
|
or (
|
||
|
(num > self.total_pages - right_edge)
|
||
|
)
|
||
|
)
|
||
|
if is_active_page:
|
||
|
if last + 1 != num:
|
||
|
yield None
|
||
|
yield num
|
||
|
last = num
|