subcategories with same basename but different parents were not unique. Fixed now.

This commit is contained in:
Alistair Magee
2014-02-01 04:50:53 +00:00
parent 614e670026
commit 250cef84f0
2 changed files with 59 additions and 21 deletions

View File

@@ -3,9 +3,7 @@
Adds support for subcategories in addition to article categories.
Subcategories are heirachial. Each subcategory has a parent, which is either a
regular category or another subcategory. Subcategories with the same name but
different parents are not the same. Their articles won't be grouped together
under that name.
regular category or another subcategory.
Feeds can be generated for each subcategory just like categories and tags.
@@ -27,16 +25,31 @@ breadcrumb style navigation you might try something like this:
<nav class="breadcrumb">
<ol>
<li>
<a href="{{ SITEURL }}/{{ arcticle.categor.url }}">{{ article.category}}</a>
<a href="{{ SITEURL }}/{{ arcticle.category.url }}">{{ article.category}}</a>
</li>
{% for subcategory in article.subcategories %}
<li>
<a href="{{ SITEURL }}/{{ category.url }}>{{ subcategory }}</a>
<a href="{{ SITEURL }}/{{ subcategory.url }}>{{ subcategory.shortname }}</a>
</li>
{% endfor %}
</ol>
</nav>
##Subcategory Names##
Each subcategory's name is a `/` seperated list of it parents and itself.
This is neccesary to keep each subcategory unique. It means you can have
`Category 1/Foo` and `Category 2/Foo` and the won't intefere with each other.
Each subcategory has an attribute `shortname` which is just the name without
it's parents associated. For example if you had
Category/Sub Category1/Sub Category2
the name for Sub Category 2 would be `Category/Sub Category1/Sub Category2` and
the shortname would be `Sub Category2`
If you need to use the slug, it is generated from the short name, not the full
name.
##Settings##

View File

@@ -6,64 +6,89 @@ Adds support for subcategories on pelican articles
"""
import os
from collections import defaultdict
from pelican import signals
from pelican.urlwrappers import URLWrapper, Category
from operator import attrgetter
from functools import partial
from pelican import signals
from pelican.urlwrappers import URLWrapper, Category
from pelican.utils import (slugify, python_2_unicode_compatible)
from six import text_type
class SubCategory(URLWrapper):
def __init__(self, name, parent, *args, **kwargs):
super(SubCategory, self).__init__(name, *args, **kwargs)
def __init__(self, name, parent, settings):
super(SubCategory, self).__init__(name, settings)
self.parent = parent
self.shortname = name.split('/')
self.shortname = self.shortname.pop()
self.slug = slugify(self.shortname, settings.get('SLUG_SUBSTITUIONS', ()))
if isinstance(self.parent, SubCategory):
self.savepath = os.path.join(self.parent.savepath, self.slug)
self.fullurl = '{}/{}'.format(self.parent.fullurl, self.slug)
else: #parent is a category
self.savepath = os.path.join(self.parent.slug, self.slug)
self.fullurl = '{}/{}'.format(self.parent.slug, self.slug)
def as_dict(self):
d = self.__dict__
d['name'] = self.name
d['shortname'] = self.shortname
d['savepath'] = self.savepath
d['fullurl'] = self.fullurl
d['parent'] = self.parent
return d
def __hash__(self):
return hash(self.fullurl)
def _key(self):
return self.fullurl
def get_subcategories(generator, metadata):
if 'SUBCATEGORY_SAVE_AS' not in generator.settings:
generator.settings['SUBCATEGORY_SAVE_AS'] = os.path.join(
'subcategory', '{savepath}.html')
if 'SUBCATEGORY_URL' not in generator.settings:
generator.settings['SUBCATEGORY_URL'] = 'subcategory/{fullurl}.html'
category_list = text_type(metadata.get('category')).split('/')
category = (category_list.pop(0)).strip()
category = Category(category, generator.settings)
metadata['category'] = category
#generate a list of subcategories with their parents
sub_list = []
parent = category
parent = category.name
for subcategory in category_list:
subcategory.strip()
subcategory = SubCategory(subcategory, parent, generator.settings)
subcategory = parent + '/' + subcategory
sub_list.append(subcategory)
parent = subcategory
metadata['subcategories'] = sub_list
def organize_subcategories(generator):
generator.subcategories = defaultdict(list)
def create_subcategories(generator):
generator.subcategories = []
for article in generator.articles:
subcategories = article.metadata.get('subcategories')
for cat in subcategories:
generator.subcategories[cat].append(article)
parent = article.category
actual_subcategories = []
for subcategory in article.subcategories:
#following line returns a list of items, tuples in this case
sub_cat = [item for item in generator.subcategories
if item[0].name == subcategory]
if sub_cat:
sub_cat[0][1].append(article)
parent = sub_cat[0][0]
actual_subcategories.append(parent)
else:
new_sub = SubCategory(subcategory, parent, generator.settings)
generator.subcategories.append((new_sub, [article,]))
parent = new_sub
actual_subcategories.append(parent)
article.subcategories = actual_subcategories
def generate_subcategories(generator, writer):
write = partial(writer.write_file,
relative_urls=generator.settings['RELATIVE_URLS'])
subcategory_template = generator.get_template('subcategory')
for subcat, articles in generator.subcategories.items():
for subcat, articles in generator.subcategories:
articles.sort(key=attrgetter('date'), reverse=True)
dates = [article for article in generator.dates if article in articles]
write(subcat.save_as, subcategory_template, generator.context,
@@ -72,7 +97,7 @@ def generate_subcategories(generator, writer):
page_name=subcat.page_name, all_articles=generator.articles)
def generate_subcategory_feeds(generator, writer):
for subcat, articles in generator.subcategories.items():
for subcat, articles in generator.subcategories:
articles.sort(key=attrgetter('date'), reverse=True)
if generator.settings.get('SUBCATEGORY_FEED_ATOM'):
writer.write_feed(articles, generator.context,
@@ -89,5 +114,5 @@ def generate(generator, writer):
def register():
signals.article_generator_context.connect(get_subcategories)
signals.article_generator_finalized.connect(organize_subcategories)
signals.article_generator_finalized.connect(create_subcategories)
signals.article_writer_finalized.connect(generate)