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.
Enso-Bot/venv/Lib/site-packages/paginator.py

153 lines
4.7 KiB
Python

"""
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