comparison piecrust/rendering.py @ 515:16e705c58cae

internal: Improve handling of taxonomy term slugification. This paves the way to bring slugification options like transliteration to PieCrust. This change mostly makes sure we use one-way slugification, which means, for serving/previewing, we need to slugify each page's terms to compare to the stuff captured from the URL. It also simplifies things a bit in the code.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 26 Jul 2015 23:16:15 -0700
parents 7d868afc6791
children bab91fcef741
comparison
equal deleted inserted replaced
514:c9c305645e5f 515:16e705c58cae
4 import logging 4 import logging
5 from werkzeug.utils import cached_property 5 from werkzeug.utils import cached_property
6 from piecrust.data.builder import ( 6 from piecrust.data.builder import (
7 DataBuildingContext, build_page_data, build_layout_data) 7 DataBuildingContext, build_page_data, build_layout_data)
8 from piecrust.data.filters import ( 8 from piecrust.data.filters import (
9 PaginationFilter, HasFilterClause, IsFilterClause, AndBooleanClause, 9 PaginationFilter, SettingFilterClause, page_value_accessor)
10 page_value_accessor)
11 from piecrust.sources.base import PageSource 10 from piecrust.sources.base import PageSource
12 from piecrust.templating.base import TemplateNotFoundError, TemplatingError 11 from piecrust.templating.base import TemplateNotFoundError, TemplatingError
13 12
14 13
15 logger = logging.getLogger(__name__) 14 logger = logging.getLogger(__name__)
165 self._raiseIfNoCurrentPass() 164 self._raiseIfNoCurrentPass()
166 if isinstance(source, PageSource): 165 if isinstance(source, PageSource):
167 pass_info = self.current_pass_info 166 pass_info = self.current_pass_info
168 pass_info.used_source_names.add(source.name) 167 pass_info.used_source_names.add(source.name)
169 168
170 def setTaxonomyFilter(self, taxonomy, term_value): 169 def setTaxonomyFilter(self, term_value):
170 if not self.page.route.is_taxonomy_route:
171 raise Exception("The page for this context is not tied to a "
172 "taxonomy route: %s" % self.uri)
173
174 taxonomy = self.app.getTaxonomy(self.page.route.taxonomy_name)
175 flt = PaginationFilter(value_accessor=page_value_accessor)
176 flt.addClause(HasTaxonomyTermsFilterClause(
177 taxonomy, term_value, self.page.route.slugifyTaxonomyTerm))
178 self.pagination_filter = flt
179
171 is_combination = isinstance(term_value, tuple) 180 is_combination = isinstance(term_value, tuple)
172 flt = PaginationFilter(value_accessor=page_value_accessor)
173 if taxonomy.is_multiple:
174 if is_combination:
175 abc = AndBooleanClause()
176 for t in term_value:
177 abc.addClause(HasFilterClause(taxonomy.setting_name, t))
178 flt.addClause(abc)
179 else:
180 flt.addClause(
181 HasFilterClause(taxonomy.setting_name, term_value))
182 else:
183 flt.addClause(IsFilterClause(taxonomy.setting_name, term_value))
184 self.pagination_filter = flt
185
186 self.custom_data = { 181 self.custom_data = {
187 taxonomy.term_name: term_value, 182 taxonomy.term_name: term_value,
188 'is_multiple_%s' % taxonomy.term_name: is_combination} 183 'is_multiple_%s' % taxonomy.term_name: is_combination}
189 184
190 def _raiseIfNoCurrentPass(self): 185 def _raiseIfNoCurrentPass(self):
191 if self._current_pass == PASS_NONE: 186 if self._current_pass == PASS_NONE:
192 raise Exception("No rendering pass is currently active.") 187 raise Exception("No rendering pass is currently active.")
188
189
190 class HasTaxonomyTermsFilterClause(SettingFilterClause):
191 def __init__(self, taxonomy, value, slugifier):
192 super(HasTaxonomyTermsFilterClause, self).__init__(
193 taxonomy.setting_name, value)
194 self._taxonomy = taxonomy
195 self._slugifier = slugifier
196 self._is_combination = isinstance(self.value, tuple)
197
198 def pageMatches(self, fil, page):
199 if self._taxonomy.is_multiple:
200 # Multiple taxonomy, i.e. it supports multiple terms, like tags.
201 page_values = fil.value_accessor(page, self.name)
202 if page_values is None or not isinstance(page_values, list):
203 return False
204
205 if self._slugifier is not None:
206 page_set = set(map(self._slugifier, page_values))
207 else:
208 page_set = set(page_values)
209
210 if self._is_combination:
211 # Multiple taxonomy, and multiple terms to match. Check that
212 # the ones to match are all in the page's terms.
213 value_set = set(self.value)
214 return value_set.issubset(page_set)
215 else:
216 # Multiple taxonomy, one term to match.
217 return self.value in page_set
218
219 # Single taxonomy. Just compare the values.
220 page_value = fil.value_accessor(page, self.name)
221 if page_value is None:
222 return False
223 if self._slugifier is not None:
224 page_value = self._slugifier(page_value)
225 return page_value == self.value
193 226
194 227
195 def render_page(ctx): 228 def render_page(ctx):
196 eis = ctx.app.env.exec_info_stack 229 eis = ctx.app.env.exec_info_stack
197 eis.pushPage(ctx.page, ctx) 230 eis.pushPage(ctx.page, ctx)