""" Custom template filter to generate a list of FlatPage suggestions for 404 pages. Usage: {% load flatpage_suggester %} {% flatpage_suggester request_path %} """ from django import template from django.contrib.flatpages.models import FlatPage from django.db.models import Q from django.template import Variable register = template.Library() class FlatPageSuggesterNode(template.Node): """ Finds FlatPages with urls 'similar' to the given request_path. This template tag takes the request_path from the page_not_found view (django.views.defaults), picks it apart, and attempts to match existing FlatPages that have a 'similar' URL. For example, if the URL that resulted in a 404 was: /foo/bar/baz/whatever/ This tag would look for FlatPages whose URL starts with the following: /foo/bar/baz/whatever/ /foo/bar/baz/ /foo/bar/ /foo/ """ def __init__(self, request_path): self.request_path = Variable(request_path) def render(self, context): output = '' request_path = self.request_path.resolve(context) # Heartily discard any extensions request_path = request_path[:request_path.rfind('.')] # Pick the path apart path_parts = [item for item in request_path.split('/') if len(item) > 0] if len(path_parts) > 0: url_list = ['/%s/' % '/'.join(path_parts)] for x in range(1, len(path_parts) - 1): url = '/'.join(path_parts[:-x]) url_list.append('/%s/' % url) # Try to find similar FlatPage objects q = Q(url__startswith=url_list[0]) # TODO: include the 'current' Site? for url in url_list[1:]: q.add(Q(url__startswith=url), Q.OR) pages = FlatPage.objects.filter(q) if pages.count() > 0: output = '

The following pages may be of interest:

' # No suggestions? Start at the beginning. if not output: output = '

Would you like start at the Home Page?

' return output def do_flatpage_suggester(parser, token): """ Parser for the flatpage_suggester Template Tag: {% flatpage_suggester request_path %} Finds FlatPages with urls 'similar' to the given request_path. """ bits = list(token.split_contents()) if len(bits) == 2: request_path = bits[1] else: raise template.TemplateSyntaxerror, "%r requires a request_path as an argument." % token.contents.split()[0] return FlatPageSuggesterNode(request_path) register.tag('flatpage_suggester', do_flatpage_suggester)