control pagination per template

This commit is contained in:
Oliver Urs Lenz 2018-07-12 13:41:05 +02:00
commit 62128fb948
8 changed files with 84 additions and 41 deletions

View file

@ -755,10 +755,6 @@ Template pages
``DIRECT_TEMPLATES`` are searched for over paths maintained in ``DIRECT_TEMPLATES`` are searched for over paths maintained in
``THEME_TEMPLATES_OVERRIDES``. ``THEME_TEMPLATES_OVERRIDES``.
.. data:: PAGINATED_DIRECT_TEMPLATES = ['index']
Provides the direct templates that should be paginated.
Metadata Metadata
======== ========
@ -1000,6 +996,11 @@ You can use the following settings to configure the pagination.
The maximum number of articles to include on a page, not including orphans. The maximum number of articles to include on a page, not including orphans.
False to disable pagination. False to disable pagination.
.. data:: PAGINATED_TEMPLATES = {'index': None, 'tag': None, 'category': None, 'author': None}
The templates to use pagination with, and the number of articles to include
on a page. If this value is ``None``, it defaults to ``DEFAULT_PAGINATION``.
.. data:: PAGINATION_PATTERNS .. data:: PAGINATION_PATTERNS
A set of patterns that are used to determine advanced pagination output. A set of patterns that are used to determine advanced pagination output.

View file

@ -456,6 +456,7 @@ class ArticlesGenerator(CachingGenerator):
# `dates` is already sorted by date # `dates` is already sorted by date
for _period, group in groupby(dates, key=key): for _period, group in groupby(dates, key=key):
archive = list(group) archive = list(group)
articles = [a for a in self.articles if a in archive]
# arbitrarily grab the first date so that the usual # arbitrarily grab the first date so that the usual
# format string syntax can be used for specifying the # format string syntax can be used for specifying the
# period archive dates # period archive dates
@ -478,8 +479,9 @@ class ArticlesGenerator(CachingGenerator):
month_name, month_name,
_period[2]) _period[2])
write(save_as, template, context, write(save_as, template, context, articles=articles,
dates=archive, blog=True, url=url) dates=archive, template_name='period_archives',
blog=True, url=url)
for period in 'year', 'month', 'day': for period in 'year', 'month', 'day':
save_as = period_save_as[period] save_as = period_save_as[period]
@ -490,11 +492,7 @@ class ArticlesGenerator(CachingGenerator):
def generate_direct_templates(self, write): def generate_direct_templates(self, write):
"""Generate direct templates pages""" """Generate direct templates pages"""
PAGINATED_TEMPLATES = self.settings['PAGINATED_DIRECT_TEMPLATES']
for template in self.settings['DIRECT_TEMPLATES']: for template in self.settings['DIRECT_TEMPLATES']:
paginated = {}
if template in PAGINATED_TEMPLATES:
paginated = {'articles': self.articles, 'dates': self.dates}
save_as = self.settings.get("%s_SAVE_AS" % template.upper(), save_as = self.settings.get("%s_SAVE_AS" % template.upper(),
'%s.html' % template) '%s.html' % template)
url = self.settings.get("%s_URL" % template.upper(), url = self.settings.get("%s_URL" % template.upper(),
@ -502,8 +500,9 @@ class ArticlesGenerator(CachingGenerator):
if not save_as: if not save_as:
continue continue
write(save_as, self.get_template(template), write(save_as, self.get_template(template), self.context,
self.context, blog=True, paginated=paginated, articles=self.articles, dates=self.dates, blog=True,
template_name=template,
page_name=os.path.splitext(save_as)[0], url=url) page_name=os.path.splitext(save_as)[0], url=url)
def generate_tags(self, write): def generate_tags(self, write):
@ -513,18 +512,18 @@ class ArticlesGenerator(CachingGenerator):
dates = [article for article in self.dates if article in articles] dates = [article for article in self.dates if article in articles]
write(tag.save_as, tag_template, self.context, tag=tag, write(tag.save_as, tag_template, self.context, tag=tag,
url=tag.url, articles=articles, dates=dates, url=tag.url, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True, template_name='tag', blog=True, page_name=tag.page_name,
page_name=tag.page_name, all_articles=self.articles) all_articles=self.articles)
def generate_categories(self, write): def generate_categories(self, write):
"""Generate category pages.""" """Generate category pages."""
category_template = self.get_template('category') category_template = self.get_template('category')
for cat, articles in self.categories: for cat, articles in self.categories:
dates = [article for article in self.dates if article in articles] dates = [article for article in self.dates if article in articles]
write(cat.save_as, category_template, self.context, write(cat.save_as, category_template, self.context, url=cat.url,
url=cat.url, category=cat, articles=articles, dates=dates, category=cat, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True, template_name='category', blog=True, page_name=cat.page_name,
page_name=cat.page_name, all_articles=self.articles) all_articles=self.articles)
def generate_authors(self, write): def generate_authors(self, write):
"""Generate Author pages.""" """Generate Author pages."""
@ -533,7 +532,7 @@ class ArticlesGenerator(CachingGenerator):
dates = [article for article in self.dates if article in articles] dates = [article for article in self.dates if article in articles]
write(aut.save_as, author_template, self.context, write(aut.save_as, author_template, self.context,
url=aut.url, author=aut, articles=articles, dates=dates, url=aut.url, author=aut, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True, template_name='author', blog=True,
page_name=aut.page_name, all_articles=self.articles) page_name=aut.page_name, all_articles=self.articles)
def generate_drafts(self, write): def generate_drafts(self, write):

View file

@ -17,15 +17,14 @@ PaginationRule = namedtuple(
class Paginator(object): class Paginator(object):
def __init__(self, name, url, object_list, settings): def __init__(self, name, url, object_list, settings, per_page=None):
self.name = name self.name = name
self.url = url self.url = url
self.object_list = object_list self.object_list = object_list
self.settings = settings self.settings = settings
if per_page:
if settings.get('DEFAULT_PAGINATION'): self.per_page = per_page
self.per_page = settings.get('DEFAULT_PAGINATION') self.orphans = settings['DEFAULT_ORPHANS']
self.orphans = settings.get('DEFAULT_ORPHANS')
else: else:
self.per_page = len(object_list) self.per_page = len(object_list)
self.orphans = 0 self.orphans = 0

View file

@ -108,7 +108,8 @@ DEFAULT_CONFIG = {
'DEFAULT_LANG': 'en', 'DEFAULT_LANG': 'en',
'DIRECT_TEMPLATES': ['index', 'tags', 'categories', 'authors', 'archives'], 'DIRECT_TEMPLATES': ['index', 'tags', 'categories', 'authors', 'archives'],
'THEME_TEMPLATES_OVERRIDES': [], 'THEME_TEMPLATES_OVERRIDES': [],
'PAGINATED_DIRECT_TEMPLATES': ['index'], 'PAGINATED_TEMPLATES': {'index': None, 'tag': None, 'category': None,
'author': None},
'PELICAN_CLASS': 'pelican.Pelican', 'PELICAN_CLASS': 'pelican.Pelican',
'DEFAULT_DATE_FORMAT': '%a %d %B %Y', 'DEFAULT_DATE_FORMAT': '%a %d %B %Y',
'DATE_FORMATS': {}, 'DATE_FORMATS': {},
@ -455,4 +456,14 @@ def configure_settings(settings):
message += ', see {} for details'.format(doc) message += ', see {} for details'.format(doc)
logger.warning(message) logger.warning(message)
if 'PAGINATED_DIRECT_TEMPLATES' in settings:
message = 'The {} setting has been removed in favor of {}'.format(
'PAGINATED_DIRECT_TEMPLATES', 'PAGINATED_TEMPLATES')
logger.warning(message)
for t in settings['PAGINATED_DIRECT_TEMPLATES']:
if t not in settings['PAGINATED_TEMPLATES']:
settings['PAGINATED_TEMPLATES'][t] = None
del settings['PAGINATED_DIRECT_TEMPLATES']
return settings return settings

View file

@ -337,8 +337,10 @@ class TestArticlesGenerator(unittest.TestCase):
generator.generate_direct_templates(write) generator.generate_direct_templates(write)
write.assert_called_with("archives.html", write.assert_called_with("archives.html",
generator.get_template("archives"), settings, generator.get_template("archives"), settings,
blog=True, paginated={}, page_name='archives', articles=generator.articles,
url="archives.html") dates=generator.dates, blog=True,
template_name='archives',
page_name='archives', url="archives.html")
@unittest.skipUnless(MagicMock, 'Needs Mock module') @unittest.skipUnless(MagicMock, 'Needs Mock module')
def test_direct_templates_save_as_url_modified(self): def test_direct_templates_save_as_url_modified(self):
@ -355,7 +357,9 @@ class TestArticlesGenerator(unittest.TestCase):
generator.generate_direct_templates(write) generator.generate_direct_templates(write)
write.assert_called_with("archives/index.html", write.assert_called_with("archives/index.html",
generator.get_template("archives"), settings, generator.get_template("archives"), settings,
blog=True, paginated={}, articles=generator.articles,
dates=generator.dates, blog=True,
template_name='archives',
page_name='archives/index', page_name='archives/index',
url="archives/") url="archives/")
@ -404,13 +408,15 @@ class TestArticlesGenerator(unittest.TestCase):
write = MagicMock() write = MagicMock()
generator.generate_period_archives(write) generator.generate_period_archives(write)
dates = [d for d in generator.dates if d.date.year == 1970] dates = [d for d in generator.dates if d.date.year == 1970]
articles = [d for d in generator.articles if d.date.year == 1970]
self.assertEqual(len(dates), 1) self.assertEqual(len(dates), 1)
# among other things it must have at least been called with this # among other things it must have at least been called with this
settings["period"] = (1970,) settings["period"] = (1970,)
write.assert_called_with("posts/1970/index.html", write.assert_called_with("posts/1970/index.html",
generator.get_template("period_archives"), generator.get_template("period_archives"),
settings, settings, blog=True, articles=articles,
blog=True, dates=dates, url="posts/1970/") dates=dates, template_name='period_archives',
url="posts/1970/")
del settings["period"] del settings["period"]
settings['MONTH_ARCHIVE_SAVE_AS'] = \ settings['MONTH_ARCHIVE_SAVE_AS'] = \
@ -425,13 +431,16 @@ class TestArticlesGenerator(unittest.TestCase):
generator.generate_period_archives(write) generator.generate_period_archives(write)
dates = [d for d in generator.dates dates = [d for d in generator.dates
if d.date.year == 1970 and d.date.month == 1] if d.date.year == 1970 and d.date.month == 1]
articles = [d for d in generator.articles
if d.date.year == 1970 and d.date.month == 1]
self.assertEqual(len(dates), 1) self.assertEqual(len(dates), 1)
settings["period"] = (1970, "January") settings["period"] = (1970, "January")
# among other things it must have at least been called with this # among other things it must have at least been called with this
write.assert_called_with("posts/1970/Jan/index.html", write.assert_called_with("posts/1970/Jan/index.html",
generator.get_template("period_archives"), generator.get_template("period_archives"),
settings, settings, blog=True, articles=articles,
blog=True, dates=dates, url="posts/1970/Jan/") dates=dates, template_name='period_archives',
url="posts/1970/Jan/")
del settings["period"] del settings["period"]
settings['DAY_ARCHIVE_SAVE_AS'] = \ settings['DAY_ARCHIVE_SAVE_AS'] = \
@ -450,13 +459,19 @@ class TestArticlesGenerator(unittest.TestCase):
d.date.month == 1 and d.date.month == 1 and
d.date.day == 1 d.date.day == 1
] ]
articles = [
d for d in generator.articles if
d.date.year == 1970 and
d.date.month == 1 and
d.date.day == 1
]
self.assertEqual(len(dates), 1) self.assertEqual(len(dates), 1)
settings["period"] = (1970, "January", 1) settings["period"] = (1970, "January", 1)
# among other things it must have at least been called with this # among other things it must have at least been called with this
write.assert_called_with("posts/1970/Jan/01/index.html", write.assert_called_with("posts/1970/Jan/01/index.html",
generator.get_template("period_archives"), generator.get_template("period_archives"),
settings, settings, blog=True, articles=articles,
blog=True, dates=dates, dates=dates, template_name='period_archives',
url="posts/1970/Jan/01/") url="posts/1970/Jan/01/")
locale.setlocale(locale.LC_ALL, old_locale) locale.setlocale(locale.LC_ALL, old_locale)

View file

@ -66,13 +66,12 @@ class TestPage(unittest.TestCase):
(1, '/{url}', '{base_name}/index.html'), (1, '/{url}', '{base_name}/index.html'),
(2, '/{url}{number}/', '{base_name}/{number}/index.html') (2, '/{url}{number}/', '{base_name}/{number}/index.html')
]] ]]
settings['DEFAULT_PAGINATION'] = 1
self.page_kwargs['metadata']['author'] = Author('Blogger', settings) self.page_kwargs['metadata']['author'] = Author('Blogger', settings)
object_list = [Article(**self.page_kwargs), object_list = [Article(**self.page_kwargs),
Article(**self.page_kwargs)] Article(**self.page_kwargs)]
paginator = Paginator('blog/index.html', '//blog.my.site/', paginator = Paginator('blog/index.html', '//blog.my.site/',
object_list, settings) object_list, settings, 1)
page1 = paginator.page(1) page1 = paginator.page(1)
self.assertEqual(page1.save_as, 'blog/index.html') self.assertEqual(page1.save_as, 'blog/index.html')
self.assertEqual(page1.url, '//blog.my.site/') self.assertEqual(page1.url, '//blog.my.site/')

View file

@ -177,6 +177,15 @@ class TestSettingsConfiguration(unittest.TestCase):
['/foo/bar', '/ha']) ['/foo/bar', '/ha'])
self.assertNotIn('EXTRA_TEMPLATES_PATHS', settings) self.assertNotIn('EXTRA_TEMPLATES_PATHS', settings)
def test_deprecated_paginated_direct_templates(self):
settings = self.settings
settings['PAGINATED_DIRECT_TEMPLATES'] = ['index', 'archives']
settings['PAGINATED_TEMPLATES'] = {'index': 10, 'category': None}
settings = configure_settings(settings)
self.assertEqual(settings['PAGINATED_TEMPLATES'],
{'index': 10, 'category': None, 'archives': None})
self.assertNotIn('PAGINATED_DIRECT_TEMPLATES', settings)
def test_theme_and_extra_templates_exception(self): def test_theme_and_extra_templates_exception(self):
settings = self.settings settings = self.settings
settings['EXTRA_TEMPLATES_PATHS'] = ['/ha'] settings['EXTRA_TEMPLATES_PATHS'] = ['/ha']

View file

@ -151,7 +151,8 @@ class Writer(object):
return feed return feed
def write_file(self, name, template, context, relative_urls=False, def write_file(self, name, template, context, relative_urls=False,
paginated=None, override_output=False, url=None, **kwargs): paginated=None, template_name=None, override_output=False,
url=None, **kwargs):
"""Render the template and write the file. """Render the template and write the file.
:param name: name of the file to output :param name: name of the file to output
@ -160,6 +161,7 @@ class Writer(object):
:param relative_urls: use relative urls or absolutes ones :param relative_urls: use relative urls or absolutes ones
:param paginated: dict of article list to paginate - must have the :param paginated: dict of article list to paginate - must have the
same length (same list in different orders) same length (same list in different orders)
:param template_name: the template name, for pagination
:param override_output: boolean telling if we can override previous :param override_output: boolean telling if we can override previous
output with the same name (and if next files written with the same output with the same name (and if next files written with the same
name should be skipped to keep that one) name should be skipped to keep that one)
@ -209,11 +211,19 @@ class Writer(object):
localcontext.update(kwargs) localcontext.update(kwargs)
return localcontext return localcontext
# pagination if paginated is None:
if paginated: paginated = {key: val for key, val in kwargs.items()
if key in {'articles', 'dates'}}
# pagination needed, init paginators # pagination
paginators = {key: Paginator(name, url, val, self.settings) if paginated and template_name in self.settings['PAGINATED_TEMPLATES']:
# pagination needed
per_page = self.settings['PAGINATED_TEMPLATES'][template_name] \
or self.settings['DEFAULT_PAGINATION']
# init paginators
paginators = {key: Paginator(name, url, val, self.settings,
per_page)
for key, val in paginated.items()} for key, val in paginated.items()}
# generated pages, and write # generated pages, and write