Original and further information available from here.
v1.1 Update (20/04/08): Added the ability to recurse single elements as well as automatic skipping of empty elements.
Most of the tags are self explanatory, the only one that may cause confusion is the main {% recurse %}
one. The format for this tag is {% recurse [children] with [parent] as [child] %}
where “[children]” is the property that contains the children of the current element, “[parent]” is your starting element and “[child]” is the variable named used in the loop.
Example usage:
{% load recurse %}
... Headers and stuff ...
{% recurse category.category_set.all with categories as category %}
<ul>
{% loop %}
<li>
<h{{ level }}>{{ category.title }}</h{{ level }}>
{% child %}
</li>
{% endloop %}
</ul>
{% endrecurse %}
... The rest of the page ...
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 | ###############################################################################
# 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)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
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
#
Please login first before commenting.