Login

Hierarchical Flatpage Tag

Author:
0sn
Posted:
November 12, 2008
Language:
Python
Version:
1.0
Score:
1 (after 1 ratings)

Two template tags (I keep them in an app called "utils") handy for building menus out of flatpages. I only have two levels of hierarchy, and the frontpage is dynamic, so that's what it does. There is some flexibility, however, in that you can change the regex that defines a "root" page.

You can pass it the flatpage object that is normally given to a flatpage template, or you can pass it a string (for any other page).

Deliberatley does not create any markup -- flexibility is key, so it adds the list of root urls or child urls as a name in the current context. You get to pick the name.

Please visit the GitHub archive where i keep this up to date, there's a better explanation and you can see it in use.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
from django import template
import re
from django.contrib.flatpages.models import FlatPage
register = template.Library()

def do_flatpage_root(parser, token):
    """
    This tag creates a queryset containing all the top-level flatpages,
    adding it to the current context with the given name.
    This does not include "/", if there is a flatpage with that url.
    
    For example::
    
        {% flatpage_root as root %}
    
    adds a queryset of flatpages whose url can be matched with ^/[^/]*/$ to
    the current context, named root. It can then be used::
    
        {% for page in root %}
        
    and so forth.
    """
    bits = token.contents.split()
    if len(bits) != 3 or bits[1] != "as":
        raise template.TemplateSyntaxError("%r expected format is 'flatpage_root as name'" % bits[0])
    return FlatpageRoot(bits[2])

class FlatpageRoot(template.Node):
    # this regex is the definition of a top-level flatpage
    # override in a subclass if you have a different idea!
    root_regex = r'^/[^/]*/$'
    def __init__(self, context_name):
        self.context_name = context_name
    def render(self, context):
        context[self.context_name] = FlatPage.objects.filter(url__regex=self.root_regex)
        return ""

register.tag('flatpage_root', do_flatpage_root)

def do_flatpage_children(parser, token):
    """
    This tag creates a queryset containing all flatpages below a given root
    url, adding it to the current context with the given name.
    
    A "root url" is any url matched by ^/[^/]*/$.
    
    Typically, this would be used to get a list of children of a parent url::
    
        {% flatpage_children "/about/" as children}
    
    This adds a queryset of all deeper urls, such as "/about/author/" and
    "/about/pants/" to the current context, named children.
    
    If the url given is "/", the tag doesn't do anything.
    
    If the url given is not a root url, for example "/about/pants/", only the
    root url portion of the argument is used. Thus, "/about/" and
    "/about/pants/" will return the same result, assuming both those flatpages
    exist.
    
    If the first argument is not in quotes, it is assumed to be in the current
    context::

        {% flatpage_children flatpage.url as children %}
    
    This adds a queryset of all urls deeper than the root url of the current
    flatpage.
    """
    bits = token.contents.split()
    if len(bits) != 4 or bits[2] != "as":
        raise template.TemplateSyntaxError("%r expected format is 'flatpage_children URL as name'" % bits[0])
    return FlatpageChildren(bits[1], bits[3])

class FlatpageChildren(template.Node):
    # this regex is the definition of a top-level flatpage
    # override in a subclass if you have a different idea!
    # note the difference from root_regex in FlatpageRoot:
    # the string is allowed to continue past the first slash...
    root_regex = r'^(/[^/]*?/)'
    def __init__(self, url, context_name):
        self.url = url
        self.context_name = context_name
    def render(self, context):
        if self.url[0] in ('"',"'"):
            if self.url[0] == self.url[-1] and len(self.url) > 3:
                urlcontent = self.url
            else:
                return ""
        else:
            urlcontent = template.Variable(self.url).resolve(context)
        m = re.search(self.root_regex, urlcontent)
        if not m:
            return ""
        root = m.group(1)
                
        context[self.context_name] = FlatPage.objects.filter(
            url__gt=root,
            url__startswith=root
        )
        return ""

register.tag('flatpage_children', do_flatpage_children)

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

0sn (on November 15, 2008):

I've since gone on to make this a context manager instead. I'll post that later.

#

Please login first before commenting.