id,summary,reporter,owner,description,type,status,component,version,severity,resolution,keywords,cc,stage,has_patch,needs_docs,needs_tests,needs_better_patch,easy,ui_ux
3544,Fix {% include %} to allow recursive includes,David Danier ,nobody,"If you try to do recursive includes (for example to display hierarchical data) the include-tag will fail, because it trys to parse the template when loading (at least ConstantIncludeNode does). This can be fixed by saving the loaded templates and avoid multiple loading. Besides this should improve performance, if templates get included multiple times inside a request. Perhaps it would be best to include some form of caching in django.template.loader.get_template?
I have created a simple RecursiveIncludeNode, which caches the loaded templates. The drawback is, that I think the cache stays in RAM over multiple requests (should be no real problem, only if very much templates are used). Also this combines ConstantIncludeNode and IncludeNode (constant templates get cached when parsing, variable templates get cached inside render()).
But I think it would be best to put caching inside the get_template()-function of django (perhaps as a special loader?), as this could improve performance (and is no real drawback).
The Code:
{{{
class RecursiveIncludeNode(Node):
cache = {}
@staticmethod
def _get_template(template_name):
if not RecursiveIncludeNode._has_template(template_name):
RecursiveIncludeNode._load_template(template_name)
return RecursiveIncludeNode.cache[template_name]
@staticmethod
def _has_template(template_name):
return RecursiveIncludeNode.cache.has_key(template_name)
@staticmethod
def _load_template(template_name):
RecursiveIncludeNode.cache[template_name] = None
try:
RecursiveIncludeNode.cache[template_name] = get_template(template_name)
except:
del RecursiveIncludeNode.cache[template_name]
raise
def __init__(self, template_name):
self.template_name = template_name
def render(self, context):
try:
template_name = resolve_variable(self.template_name, context)
t = RecursiveIncludeNode._get_template(template_name)
return t.render(context)
except TemplateSyntaxError, e:
if settings.TEMPLATE_DEBUG:
raise
return ''
except:
return '' # Fail silently for invalid included templates.
def rec_include(parser, token):
bits = token.contents.split()
if len(bits) != 2:
raise TemplateSyntaxError, ""%r tag takes one argument: the name of the template to be included"" % bits[0]
path = bits[1]
from django.template.loader_tags import IncludeNode
if path[0] in ('""', ""'"") and path[-1] == path[0]:
template_name = path[1:-1]
if not RecursiveIncludeNode._has_template(template_name):
RecursiveIncludeNode._load_template(template_name)
return RecursiveIncludeNode(bits[1])
register.tag('rec_include', rec_include)
}}}
",New feature,closed,Template system,master,Normal,fixed,tplrf-patched,flavio.curella@… Erik Allik david@… Mike Fogel newmaniese@… cvrebert FunkyBob,Ready for checkin,1,0,0,0,0,0