Mercurial > piecrust2
changeset 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 | c9c305645e5f |
children | 73bd408caebc |
files | piecrust/baking/single.py piecrust/rendering.py piecrust/routing.py piecrust/serving/server.py tests/test_serving.py |
diffstat | 5 files changed, 71 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/piecrust/baking/single.py Sun Jul 26 23:05:04 2015 -0700 +++ b/piecrust/baking/single.py Sun Jul 26 23:16:15 2015 -0700 @@ -157,8 +157,7 @@ def _bakeSingle(self, qualified_page, num, out_path, tax_info=None): ctx = PageRenderingContext(qualified_page, page_num=num) if tax_info: - tax = self.app.getTaxonomy(tax_info.taxonomy_name) - ctx.setTaxonomyFilter(tax, tax_info.term) + ctx.setTaxonomyFilter(tax_info.term) rp = render_page(ctx)
--- a/piecrust/rendering.py Sun Jul 26 23:05:04 2015 -0700 +++ b/piecrust/rendering.py Sun Jul 26 23:16:15 2015 -0700 @@ -6,8 +6,7 @@ from piecrust.data.builder import ( DataBuildingContext, build_page_data, build_layout_data) from piecrust.data.filters import ( - PaginationFilter, HasFilterClause, IsFilterClause, AndBooleanClause, - page_value_accessor) + PaginationFilter, SettingFilterClause, page_value_accessor) from piecrust.sources.base import PageSource from piecrust.templating.base import TemplateNotFoundError, TemplatingError @@ -167,22 +166,18 @@ pass_info = self.current_pass_info pass_info.used_source_names.add(source.name) - def setTaxonomyFilter(self, taxonomy, term_value): - is_combination = isinstance(term_value, tuple) + def setTaxonomyFilter(self, term_value): + if not self.page.route.is_taxonomy_route: + raise Exception("The page for this context is not tied to a " + "taxonomy route: %s" % self.uri) + + taxonomy = self.app.getTaxonomy(self.page.route.taxonomy_name) flt = PaginationFilter(value_accessor=page_value_accessor) - if taxonomy.is_multiple: - if is_combination: - abc = AndBooleanClause() - for t in term_value: - abc.addClause(HasFilterClause(taxonomy.setting_name, t)) - flt.addClause(abc) - else: - flt.addClause( - HasFilterClause(taxonomy.setting_name, term_value)) - else: - flt.addClause(IsFilterClause(taxonomy.setting_name, term_value)) + flt.addClause(HasTaxonomyTermsFilterClause( + taxonomy, term_value, self.page.route.slugifyTaxonomyTerm)) self.pagination_filter = flt + is_combination = isinstance(term_value, tuple) self.custom_data = { taxonomy.term_name: term_value, 'is_multiple_%s' % taxonomy.term_name: is_combination} @@ -192,6 +187,44 @@ raise Exception("No rendering pass is currently active.") +class HasTaxonomyTermsFilterClause(SettingFilterClause): + def __init__(self, taxonomy, value, slugifier): + super(HasTaxonomyTermsFilterClause, self).__init__( + taxonomy.setting_name, value) + self._taxonomy = taxonomy + self._slugifier = slugifier + self._is_combination = isinstance(self.value, tuple) + + def pageMatches(self, fil, page): + if self._taxonomy.is_multiple: + # Multiple taxonomy, i.e. it supports multiple terms, like tags. + page_values = fil.value_accessor(page, self.name) + if page_values is None or not isinstance(page_values, list): + return False + + if self._slugifier is not None: + page_set = set(map(self._slugifier, page_values)) + else: + page_set = set(page_values) + + if self._is_combination: + # Multiple taxonomy, and multiple terms to match. Check that + # the ones to match are all in the page's terms. + value_set = set(self.value) + return value_set.issubset(page_set) + else: + # Multiple taxonomy, one term to match. + return self.value in page_set + + # Single taxonomy. Just compare the values. + page_value = fil.value_accessor(page, self.name) + if page_value is None: + return False + if self._slugifier is not None: + page_value = self._slugifier(page_value) + return page_value == self.value + + def render_page(ctx): eis = ctx.app.env.exec_info_stack eis.pushPage(ctx.page, ctx)
--- a/piecrust/routing.py Sun Jul 26 23:05:04 2015 -0700 +++ b/piecrust/routing.py Sun Jul 26 23:16:15 2015 -0700 @@ -42,6 +42,7 @@ self.source_name = cfg['source'] self.taxonomy_name = cfg.get('taxonomy') + self.taxonomy_term_sep = cfg.get('term_separator', '/') self.pretty_urls = app.config.get('site/pretty_urls') self.trailing_slash = app.config.get('site/trailing_slash') @@ -191,19 +192,26 @@ return uri + def getTaxonomyTerms(self, route_metadata): + if not self.is_taxonomy_route: + raise Exception("This route isn't a taxonomy route.") + + tax = self.app.getTaxonomy(self.taxonomy_name) + all_values = route_metadata.get(tax.term_name) + if all_values is None: + raise Exception("'%s' values couldn't be found in route metadata" % + tax.term_name) + + if self.taxonomy_term_sep in all_values: + return tuple(all_values.split(self.taxonomy_term_sep)) + return all_values + def slugifyTaxonomyTerm(self, term): #TODO: add options for transliterating and combining terms. if isinstance(term, tuple): return '/'.join(term) return term - def unslugifyTaxonomyTerm(self, term): - #TODO: same as above. - split_terms = term.split('/') - if len(split_terms) == 1: - return term - return tuple(split_terms) - def _uriFormatRepl(self, m): name = m.group('name') #TODO: fix this hard-coded shit
--- a/piecrust/serving/server.py Sun Jul 26 23:05:04 2015 -0700 +++ b/piecrust/serving/server.py Sun Jul 26 23:16:15 2015 -0700 @@ -321,11 +321,11 @@ if route_terms is None: return None + tax_terms = route.getTaxonomyTerms(route_metadata) + taxonomy_info = (taxonomy, tax_terms) + tax_page_ref = taxonomy.getPageRef(source) factory = tax_page_ref.getFactory() - tax_terms = route.unslugifyTaxonomyTerm(route_terms) - route_metadata[taxonomy.term_name] = tax_terms - taxonomy_info = (taxonomy, tax_terms) # Build the page. page = factory.buildPage() @@ -336,8 +336,8 @@ page_num=page_num, force_render=True) if taxonomy_info is not None: - taxonomy, tax_terms = taxonomy_info - render_ctx.setTaxonomyFilter(taxonomy, tax_terms) + _, tax_terms = taxonomy_info + render_ctx.setTaxonomyFilter(tax_terms) # See if this page is known to use sources. If that's the case, # just don't use cached rendered segments for that page (but still
--- a/tests/test_serving.py Sun Jul 26 23:05:04 2015 -0700 +++ b/tests/test_serving.py Sun Jul 26 23:16:15 2015 -0700 @@ -77,11 +77,10 @@ page = app.getSource('pages').getPage({'slug': '_tag', 'tag': tag}) route = app.getTaxonomyRoute('tags', 'posts') route_metadata = {'slug': '_tag', 'tag': tag} - taxonomy = app.getTaxonomy('tags') qp = QualifiedPage(page, route, route_metadata) ctx = PageRenderingContext(qp) - ctx.setTaxonomyFilter(taxonomy, tag) + ctx.setTaxonomyFilter(tag) rp = render_page(ctx) expected = "Pages in %s\n" % tag @@ -122,11 +121,10 @@ 'category': category}) route = app.getTaxonomyRoute('categories', 'posts') route_metadata = {'slug': '_category', 'category': category} - taxonomy = app.getTaxonomy('categories') qp = QualifiedPage(page, route, route_metadata) ctx = PageRenderingContext(qp) - ctx.setTaxonomyFilter(taxonomy, category) + ctx.setTaxonomyFilter(category) rp = render_page(ctx) expected = "Pages in %s\n" % category