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)
Comments
I've since gone on to make this a context manager instead. I'll post that later.
#