Created
March 31, 2016 22:40
-
-
Save nffdiogosilva/584238ae97ea4ba1b893a6de22272251 to your computer and use it in GitHub Desktop.
A paginator class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding:utf-8 -*- | |
from __future__ import unicode_literals | |
class Paginator(object): | |
""" | |
Class that defines a Paginator. | |
""" | |
def __init__(self, current_page, total_pages, boundaries=1, around=0, fail_silently=False): | |
self.fail_silently = fail_silently | |
# Initialize private attributes | |
self._total_pages = None | |
self._current_page = None | |
self._boundaries = None | |
self._around = None | |
self.total_pages = total_pages | |
self.current_page = current_page | |
self.boundaries = boundaries | |
self.around = around | |
self._pagination_list = [] | |
self.pagination_list = [] | |
@property | |
def current_page(self): | |
return self._current_page | |
@property | |
def total_pages(self): | |
return self._total_pages | |
@property | |
def around(self): | |
return self._around | |
@property | |
def boundaries(self): | |
return self._boundaries | |
@current_page.setter | |
def current_page(self, value): | |
if self.fail_silently: | |
# Takes into account when current_page value is smaller than 1 and bigger than total_pages value | |
value = max(1, min(self.total_pages, value)) | |
else: | |
if value < 1: | |
raise ValueError("Current page value can't be smaller than 1") | |
if value > self.total_pages: | |
raise ValueError("Current page value can't be bigger than total_pages value") | |
self._current_page = value | |
@total_pages.setter | |
def total_pages(self, value): | |
if self.fail_silently: | |
# Takes into account when total_pages is smaller than 1 | |
value = max(1, value) | |
else: | |
if value < 1: | |
raise ValueError("Total pages value can't be smaller than 1") | |
self._total_pages = value | |
@around.setter | |
def around(self, value): | |
if self.fail_silently: | |
# Takes into account when around is smaller than 0 and bigger than total_pages | |
value = max(0, min(self.total_pages, value)) | |
else: | |
if value < 0: | |
raise ValueError("Around value can't be smaller than 0") | |
if value > self.total_pages: | |
raise ValueError("Around value can't be bigger than total_pages value") | |
self._around = value | |
@boundaries.setter | |
def boundaries(self, value): | |
if self.fail_silently: | |
# Takes into account when boundaries is smaller than 0 and when is bigger than total_pages value | |
value = max(1, min(self.total_pages, value)) | |
else: | |
if value < 1: | |
raise ValueError("Boundaries value can't be smaller than 1") | |
if value > self.total_pages: | |
raise ValueError("Boundaries value can't be bigger than total_pages value") | |
self._boundaries = value | |
def _add_ellipsis_to_pagination_list(self): | |
""" | |
Initialize a pagination list with ellipses for omitted values. | |
:return: The final pagination list, with ellipses, if necessary. | |
""" | |
final_pagination_list = [] | |
for index, number in enumerate(self._pagination_list): | |
final_pagination_list.append(str(number)) | |
if index + 1 < len(self._pagination_list): | |
if self._pagination_list[index] + 1 != self._pagination_list[index + 1]: | |
final_pagination_list.append('...') | |
return final_pagination_list | |
def _clean_arounds(self, arounds_list): | |
""" | |
Removes any number that is already included in boundaries lists (0 included). | |
:param arounds_list: A list with arounds values in it. | |
:return: A cleaned arounds list, with no boundaries or zero values in it. | |
""" | |
for boundary_list in self.get_boundaries(): | |
arounds_list = [around for around in arounds_list if around not in boundary_list] | |
if 0 in arounds_list: | |
arounds_list.remove(0) | |
return arounds_list | |
def _clean_boundaries(self, boundaries_list): | |
""" | |
Removes current page from boundary list, if found it. | |
:param boundaries_list: A list with boundaries values in it. | |
:return: A cleaned boundaries list, without the current page value. | |
""" | |
if self.current_page in boundaries_list: | |
boundaries_list.remove(self.current_page) | |
return boundaries_list | |
def get_arounds(self): | |
""" | |
Calculates left and right arounds. | |
:return: A tuple with two lists: a list for each left and right arounds. | |
""" | |
current_page_min_range = max(1, self.current_page - 1) | |
current_page_max_range = min(self.current_page + 1, self.total_pages) | |
max_range = max(1, self.current_page - self.around - 1) | |
min_range = min(self.total_pages, self.current_page + self.around + 1) | |
left_arounds = sorted(range(current_page_min_range, max_range, -1), reverse=False) | |
right_arounds = range(current_page_max_range, min_range) | |
return self._clean_arounds(left_arounds), self._clean_arounds(right_arounds) | |
def get_boundaries(self): | |
""" | |
Calculates left and right boundaries. | |
:return: A tuple with two lists: a list for each left and right boundaries. | |
""" | |
left_boundaries = range(1, self.boundaries + 1) | |
left_boundaries = [boundary for boundary in left_boundaries if boundary < self.current_page] or [1] | |
right_boundaries = sorted(range(self.total_pages, self.total_pages - self.boundaries, -1), reverse=False) | |
right_boundaries = [boundary for boundary in right_boundaries if boundary > self.current_page] or [self.total_pages] | |
return self._clean_boundaries(left_boundaries), self._clean_boundaries(right_boundaries) | |
def set_pagination_list(self): | |
""" | |
Initializes a pagination list given the current object arguments. | |
:return: A pagination list | |
""" | |
self._pagination_list = self.get_boundaries()[0] + self.get_arounds()[0] + [self.current_page] + \ | |
self.get_arounds()[1] + self.get_boundaries()[1] | |
self.pagination_list = self._add_ellipsis_to_pagination_list() | |
return self.pagination_list | |
def next_page(self): | |
""" | |
Sets the next page as the current page | |
:return: The Paginator instance (updated) | |
""" | |
if self.current_page + 1 <= self.total_pages: | |
self.current_page += 1 | |
else: | |
if self.fail_silently: | |
self.current_page = self.total_pages | |
else: | |
raise ValueError("Current page value can't be bigger than total pages value") | |
self.pagination_list = self.set_pagination_list() | |
return self | |
def previous_page(self): | |
""" | |
Sets the previous page as the current page | |
:return: The Paginator instance (updated) | |
""" | |
if self.current_page - 1 >= 1: | |
self.current_page -= 1 | |
else: | |
if self.fail_silently: | |
self.current_page = 1 | |
else: | |
raise ValueError("Current page value can't be smaller than 1") | |
self.pagination_list = self.set_pagination_list() | |
return self | |
def __str__(self): | |
return ' '.join(self.set_pagination_list()) | |
def __repr__(self): | |
return 'Paginator: {0}'.format(self.__str__()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment