The model itself is fine and there are some good posts about how to do
such things around (i.e. http://swixel.net/2009/01/01/django-nested-categories-blogging-like-wordpress-again/)
The thing I'm having trouble wrapping my head around is how would I
setup URL Patterns for nested catagories when it may have any number
of extra layers?
Say I had a set of nested catagories like
Parent
- Child Level 1
- Child Level 2
which I would expect to have a url like:
<base>/parent/child-level-1/child-level-2/
Is it possible to even pick up a variable number of URL attributes
like that?
I suppose I could do something like r'^(?P<path>.*)$' and then parse
path in the view but this could wreak havoc with other URLs.
Anyone have any ideas?
Yes, that's the way to do it. You can prevent it from clashing with
other URLs by prefixing it with something like categories/ so the URL
would be:
www.example.com/categories/category-1/category-2/
That being said, it's not entirely trivial to retrieve the nested
categories. I can think of 2 basic strategies:
1. Create a "path" field on the Category model that stores the full
path (category-1/category-2). This makes it very easy to find the
category:
Category.objects.get(path=path)
But this also means you have to build the path and store it every time
a category is saved, or one of its parent categories is saved.
2. Split apart the path (path.split("/")) then loop through each part,
and see if the category exists. In pseudocode, might look like this:
for part in path.split("/"):
find category by part=part, parent=previous_part
if not found, raise 404
previous_part = part
This doesn't require any special code when saving a category, but
makes it a heck of a lot more difficult to retrieve a category.
Personally I'd go with the first option.
Specifically, check out the save() method that builds the path based
on all the parent categories if it doesn't exist.
http://code.google.com/p/django-simplecms/source/browse/trunk/simplecms/cms/models.py#47
I already have a custom save method on the Catagory for slugs so it'll
be easy enough to create a path.
I may not understand the suggested implementation very well but it
sounds like I may not have to do a split at all if I store the
sluggified path then I think all I should have to do is query on that?
I'll give it a try and try to post what I've come up with back here so
others can reference it. Thanks again.
> http://code.google.com/p/django-simplecms/source/browse/trunk/simplec...
Note I call my categories model Topics instead but you get the
picture.
class Topic(models.Model):
'''
Topics form sections and categories of posts to enable topical
based
conversations.
'''
text = models.CharField(max_length=75)
parent = models.ForeignKey('self', null=True, blank=True) # Enable
topic structures.
description = models.TextField(null=True, blank=True)
slug = models.CharField(max_length=75)
path = models.CharField(max_length=255)
# Custom manager for returning published posts.
objects = TopicManager()
def get_path(self):
'''
Constructs the path value for this topic based on hierarchy.
'''
ontology = []
target = self.parent
while(target is not None):
ontology.append(target.slug)
target = target.parent
ontology.append(self.slug)
return '/'.join(ontology)
def save(self, force_insert=False, force_update=False):
'''
Custom save method to handle slugs and such.
'''
# Set pub_date if none exist and publish is true.
if not self.slug:
qs = Topic.objects.filter(parent=self.parent)
unique_slugify(self, self.text, queryset=qs) # Unique for
each parent.
# Raise validation error if trying to create slug duplicate
under parent.
if
Topic.objects.exclude(pk=self.pk).filter(parent=self.parent,
slug=self.slug):
raise ValidationError("Slugs cannot be duplicated under
the same parent topic.")
self.path = self.get_path() # Rebuild the path attribute
whenever saved.
super(Topic, self).save(force_insert, force_update) # Actual
Save method.
def __unicode__(self):
'''Returns the name of the Topic as a it's chained
relationship.'''
ontology = []
target = self.parent
while(target is not None):
ontology.append(target.text)
target = target.parent
ontology.append(self.text)
return ' - '.join(ontology)
class Meta:
ordering = ['path']
unique_together = (('slug', 'parent'))
On Apr 7, 8:34 pm, Tim Shaffer <t...@tim-shaffer.com> wrote:
> http://code.google.com/p/django-simplecms/source/browse/trunk/simplec...