Mercurial > piecrust2
view piecrust/data/paginator.py @ 1143:1c324407bd1f
internal: Cleanup in the paginator's code.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 05 Jun 2018 21:59:41 -0700 |
parents | 492b66482f12 |
children |
line wrap: on
line source
import math import logging from werkzeug.utils import cached_property from piecrust.sources.base import ContentSource logger = logging.getLogger(__name__) class Paginator(object): debug_render = [ 'has_more', 'items', 'has_items', 'items_per_page', 'items_this_page', 'prev_page_number', 'this_page_number', 'next_page_number', 'prev_page', 'next_page', 'total_item_count', 'total_page_count', 'next_item', 'prev_item'] debug_render_invoke = [ 'has_more', 'items', 'has_items', 'items_per_page', 'items_this_page', 'prev_page_number', 'this_page_number', 'next_page_number', 'prev_page', 'next_page', 'total_item_count', 'total_page_count', 'next_item', 'prev_item'] def __init__(self, source, current_page, sub_num, *, pgn_filter=None, items_per_page=-1): self._source = source self._page = current_page self._sub_num = sub_num self._iterator = None self._pgn_filter = pgn_filter self._items_per_page = items_per_page self._pgn_set_on_ctx = False self._is_content_source = isinstance(source, ContentSource) @property def is_loaded(self): return self._iterator is not None @property def has_more(self): return self.next_page_number is not None @property def unload(self): self._iterator = None # Backward compatibility with PieCrust 1.0 {{{ @property def posts(self): return self.items @property def has_posts(self): return self.has_items @property def posts_per_page(self): return self.items_per_page @property def posts_this_page(self): return self.items_this_page @property def total_post_count(self): return self.total_item_count @property def next_post(self): return self.next_item @property def prev_post(self): return self.prev_item # }}} @property def items(self): self._load() return self._iterator @property def has_items(self): return self.items_this_page > 0 @cached_property def items_per_page(self): if self._items_per_page > 0: return self._items_per_page if self._page is not None: ipp = self._page.config.get('items_per_page') if ipp is not None: return ipp if self._is_content_source: ipp = self._source.config.get('items_per_page') if ipp is not None: return ipp raise Exception("No way to figure out how many items to display " "per page.") @property def items_this_page(self): self._load() return len(self._iterator) @property def prev_page_number(self): if self._sub_num > 1: return self._sub_num - 1 return None @property def this_page_number(self): return self._sub_num @property def next_page_number(self): self._load() if self._iterator._has_more: return self._sub_num + 1 return None @property def prev_page(self): num = self.prev_page_number if num is not None: return self._getPageUri(num) return None @property def this_page(self): return self._getPageUri(self._sub_num) @property def next_page(self): num = self.next_page_number if num is not None: return self._getPageUri(num) return None @property def total_item_count(self): self._load() return self._iterator.total_count @property def total_page_count(self): total_count = self.total_item_count per_page = self.items_per_page return int(math.ceil(total_count / per_page)) @property def next_item(self): self._load() return self._iterator.prev_page @property def prev_item(self): self._load() return self._iterator.next_page def all_page_numbers(self, radius=-1): total_page_count = self.total_page_count if total_page_count == 0: return [] if radius <= 0 or total_page_count < (2 * radius + 1): return list(range(1, total_page_count + 1)) first_num = self._sub_num - radius last_num = self._sub_num + radius if first_num <= 0: last_num += 1 - first_num first_num = 1 elif last_num > total_page_count: first_num -= (last_num - total_page_count) last_num = total_page_count first_num = max(1, first_num) last_num = min(total_page_count, last_num) return list(range(first_num, last_num + 1)) def page(self, index): return self._getPageUri(index) def _load(self): if self._iterator is not None: return from piecrust.data.filters import PaginationFilter from piecrust.dataproviders.pageiterator import ( PageIterator, HardCodedFilterIterator) self._iterator = PageIterator( self._source, current_page=self._page) if self._pgn_filter is not None: pag_fil = PaginationFilter() pag_fil.addClause(self._pgn_filter.root_clause) self._iterator._simpleNonSortedWrap( HardCodedFilterIterator, pag_fil) offset = (self._sub_num - 1) * self.items_per_page limit = self.items_per_page self._iterator.slice(offset, limit) if self._is_content_source: self._iterator._iter_event += self._onIteration self._iterator._lockIterator() def _getPageUri(self, index): return self._page.getUri(index) def _onIteration(self, it): if not self._pgn_set_on_ctx: rcs = self._source.app.env.render_ctx_stack if rcs.current_ctx is not None: rcs.current_ctx.setPagination(self) self._pgn_set_on_ctx = True