###############################################################################
# Recurse template tag for Django v1.1
# Copyright (C) 2008 Lucas Murray
# http://www.undefinedfire.com
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
###############################################################################
from django import template
register = template.Library()
class RecurseNode(template.Node):
def __init__(self, var, name, child, nodeList):
self.var = var
self.name = name
self.child = child
self.nodeList = nodeList
def __repr__(self):
return '<RecurseNode>'
def renderCallback(self, context, vals, level):
output = []
try:
if len(vals):
pass
except:
vals = [vals]
if len(vals):
if 'loop' in self.nodeList:
output.append(self.nodeList['loop'].render(context))
for val in vals:
context.push()
context['level'] = level
context[self.name] = val
if 'child' in self.nodeList:
output.append(self.nodeList['child'].render(context))
child = self.child.resolve(context)
if child:
output.append(self.renderCallback(context, child, level + 1))
if 'endloop' in self.nodeList:
output.append(self.nodeList['endloop'].render(context))
else:
output.append(self.nodeList['endrecurse'].render(context))
context.pop()
if 'endloop' in self.nodeList:
output.append(self.nodeList['endrecurse'].render(context))
return ''.join(output)
def render(self, context):
vals = self.var.resolve(context)
output = self.renderCallback(context, vals, 1)
return output
def do_recurse(parser, token):
bits = list(token.split_contents())
if len(bits) != 6 and bits[2] != 'with' and bits[4] != 'as':
raise template.TemplateSyntaxError, "Invalid tag syxtax expected '{% recurse [childVar] with [parents] as [parent] %}'"
child = parser.compile_filter(bits[1])
var = parser.compile_filter(bits[3])
name = bits[5]
nodeList = {}
while len(nodeList) < 4:
temp = parser.parse(('child','loop','endloop','endrecurse'))
tag = parser.tokens[0].contents
nodeList[tag] = temp
parser.delete_first_token()
if tag == 'endrecurse':
break
return RecurseNode(var, name, child, nodeList)
do_recurse = register.tag('recurse', do_recurse)
Comments
I changed line 33 to read as:
this allows as root list or a root object
#
actually added it above line 33
#
Thanks for that modification, I'll add it to the code.
Just came across an error caused by that bug. =)
#
thanx! i'll give you thousands of internets for this!
#
I believe the conditional on line 71 uses incorrect boolean operators. 'Or' should be used instead of 'and'. The code should raise a template syntax error if any of the conditions is True, not only when all the conditions are True:
#
Just got this working, and it's pretty fantastic...
One question though - does the {% child %} tag have to be a direct child of the {% loop %} tag?
When I tried surrounding it with a simple {% if X %} ... {% endif %} I got this template error:
"Invalid block tag: 'child'"
#
awesome
#