Mercurial > piecrust2
comparison piecrust/data/paginator.py @ 853:f070a4fc033c
core: Continue PieCrust3 refactor, simplify pages.
The asset pipeline is still the only function pipeline at this point.
* No more `QualifiedPage`, and several other pieces of code deleted.
* Data providers are simpler and more focused. For instance, the page iterator
doesn't try to support other types of items.
* Route parameters are proper known source metadata to remove the confusion
between the two.
* Make the baker and pipeline more correctly manage records and record
histories.
* Add support for record collapsing and deleting stale outputs in the asset
pipeline.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 21 May 2017 00:06:59 -0700 |
parents | 4850f8c21b6e |
children | 08e02c2a2a1a |
comparison
equal
deleted
inserted
replaced
852:4850f8c21b6e | 853:f070a4fc033c |
---|---|
1 import math | 1 import math |
2 import logging | 2 import logging |
3 from werkzeug.utils import cached_property | 3 from werkzeug.utils import cached_property |
4 from piecrust.data.filters import PaginationFilter, page_value_accessor | |
5 from piecrust.data.iterators import PageIterator | |
6 from piecrust.sources.interfaces import IPaginationSource | |
7 | 4 |
8 | 5 |
9 logger = logging.getLogger(__name__) | 6 logger = logging.getLogger(__name__) |
10 | 7 |
11 | 8 |
21 'items_this_page', 'prev_page_number', 'this_page_number', | 18 'items_this_page', 'prev_page_number', 'this_page_number', |
22 'next_page_number', 'prev_page', 'next_page', | 19 'next_page_number', 'prev_page', 'next_page', |
23 'total_item_count', 'total_page_count', | 20 'total_item_count', 'total_page_count', |
24 'next_item', 'prev_item'] | 21 'next_item', 'prev_item'] |
25 | 22 |
26 def __init__(self, qualified_page, source, *, | 23 def __init__(self, source, current_page, sub_num, *, |
27 pgn_filter=None, items_per_page=-1): | 24 pgn_filter=None, items_per_page=-1): |
28 self._parent_page = qualified_page | |
29 self._page_num = qualified_page.page_num | |
30 self._source = source | 25 self._source = source |
26 self._page = current_page | |
27 self._sub_num = sub_num | |
31 self._iterator = None | 28 self._iterator = None |
32 self._pgn_filter = pgn_filter | 29 self._pgn_filter = pgn_filter |
33 self._items_per_page = items_per_page | 30 self._items_per_page = items_per_page |
34 self._pgn_set_on_ctx = False | 31 self._pgn_set_on_ctx = False |
35 | 32 |
86 | 83 |
87 @cached_property | 84 @cached_property |
88 def items_per_page(self): | 85 def items_per_page(self): |
89 if self._items_per_page > 0: | 86 if self._items_per_page > 0: |
90 return self._items_per_page | 87 return self._items_per_page |
91 if self._parent_page: | 88 |
92 ipp = self._parent_page.page.config.get('items_per_page') | 89 ipp = self._page.config.get('items_per_page') |
93 if ipp is not None: | 90 if ipp is not None: |
94 return ipp | 91 return ipp |
95 if isinstance(self._source, IPaginationSource): | 92 |
96 return self._source.getItemsPerPage() | |
97 raise Exception("No way to figure out how many items to display " | 93 raise Exception("No way to figure out how many items to display " |
98 "per page.") | 94 "per page.") |
99 | 95 |
100 @property | 96 @property |
101 def items_this_page(self): | 97 def items_this_page(self): |
102 self._load() | 98 self._load() |
103 return len(self._iterator) | 99 return len(self._iterator) |
104 | 100 |
105 @property | 101 @property |
106 def prev_page_number(self): | 102 def prev_page_number(self): |
107 if self._page_num > 1: | 103 if self._sub_num > 1: |
108 return self._page_num - 1 | 104 return self._sub_num - 1 |
109 return None | 105 return None |
110 | 106 |
111 @property | 107 @property |
112 def this_page_number(self): | 108 def this_page_number(self): |
113 return self._page_num | 109 return self._sub_num |
114 | 110 |
115 @property | 111 @property |
116 def next_page_number(self): | 112 def next_page_number(self): |
117 self._load() | 113 self._load() |
118 if self._iterator._has_more: | 114 if self._iterator._has_more: |
119 return self._page_num + 1 | 115 return self._sub_num + 1 |
120 return None | 116 return None |
121 | 117 |
122 @property | 118 @property |
123 def prev_page(self): | 119 def prev_page(self): |
124 num = self.prev_page_number | 120 num = self.prev_page_number |
126 return self._getPageUri(num) | 122 return self._getPageUri(num) |
127 return None | 123 return None |
128 | 124 |
129 @property | 125 @property |
130 def this_page(self): | 126 def this_page(self): |
131 return self._getPageUri(self._page_num) | 127 return self._getPageUri(self._sub_num) |
132 | 128 |
133 @property | 129 @property |
134 def next_page(self): | 130 def next_page(self): |
135 num = self.next_page_number | 131 num = self.next_page_number |
136 if num is not None: | 132 if num is not None: |
164 return [] | 160 return [] |
165 | 161 |
166 if radius <= 0 or total_page_count < (2 * radius + 1): | 162 if radius <= 0 or total_page_count < (2 * radius + 1): |
167 return list(range(1, total_page_count + 1)) | 163 return list(range(1, total_page_count + 1)) |
168 | 164 |
169 first_num = self._page_num - radius | 165 first_num = self._sub_num - radius |
170 last_num = self._page_num + radius | 166 last_num = self._sub_num + radius |
171 if first_num <= 0: | 167 if first_num <= 0: |
172 last_num += 1 - first_num | 168 last_num += 1 - first_num |
173 first_num = 1 | 169 first_num = 1 |
174 elif last_num > total_page_count: | 170 elif last_num > total_page_count: |
175 first_num -= (last_num - total_page_count) | 171 first_num -= (last_num - total_page_count) |
183 | 179 |
184 def _load(self): | 180 def _load(self): |
185 if self._iterator is not None: | 181 if self._iterator is not None: |
186 return | 182 return |
187 | 183 |
188 if self._source is None: | 184 from piecrust.data.filters import PaginationFilter |
189 raise Exception("Can't load pagination data: no source has " | 185 from piecrust.dataproviders.page_iterator import PageIterator |
190 "been defined.") | 186 |
191 | 187 pag_filter = PaginationFilter() |
192 pag_filter = self._getPaginationFilter() | 188 if self._pgn_filter is not None: |
193 offset = (self._page_num - 1) * self.items_per_page | 189 pag_filter.addClause(self._pgn_filter.root_clause) |
194 current_page = None | 190 |
195 if self._parent_page: | |
196 current_page = self._parent_page.page | |
197 self._iterator = PageIterator( | 191 self._iterator = PageIterator( |
198 self._source, | 192 self._source, |
199 current_page=current_page, | 193 current_page=self._page, |
200 pagination_filter=pag_filter, | 194 pagination_filter=pag_filter, |
201 offset=offset, limit=self.items_per_page, | |
202 locked=True) | 195 locked=True) |
203 self._iterator._iter_event += self._onIteration | 196 self._iterator._iter_event += self._onIteration |
204 | 197 |
205 def _getPaginationFilter(self): | 198 offset = (self._sub_num - 1) * self.items_per_page |
206 f = PaginationFilter(value_accessor=page_value_accessor) | 199 limit = self.items_per_page |
207 | 200 self._iterator.slice(offset, limit) |
208 if self._pgn_filter is not None: | |
209 f.addClause(self._pgn_filter.root_clause) | |
210 | |
211 if self._parent_page and isinstance(self._source, IPaginationSource): | |
212 sf = self._source.getPaginationFilter(self._parent_page) | |
213 if sf is not None: | |
214 f.addClause(sf.root_clause) | |
215 | |
216 return f | |
217 | 201 |
218 def _getPageUri(self, index): | 202 def _getPageUri(self, index): |
219 return self._parent_page.getUri(index) | 203 return self._page.getUri(index) |
220 | 204 |
221 def _onIteration(self): | 205 def _onIteration(self): |
222 if self._parent_page is not None and not self._pgn_set_on_ctx: | 206 if not self._pgn_set_on_ctx: |
223 eis = self._parent_page.app.env.exec_info_stack | 207 eis = self._page.app.env.exec_info_stack |
224 eis.current_page_info.render_ctx.setPagination(self) | 208 eis.current_page_info.render_ctx.setPagination(self) |
225 self._pgn_set_on_ctx = True | 209 self._pgn_set_on_ctx = True |
226 | 210 |