Index: /Users/go/working_copies/django/django/template/signals.py
===================================================================
--- /Users/go/working_copies/django/django/template/signals.py	(revision 0)
+++ /Users/go/working_copies/django/django/template/signals.py	(revision 0)
@@ -0,0 +1,2 @@
+request_finished = object()
+got_request_exception = object()
Index: /Users/go/working_copies/django/django/template/loader_tags.py
===================================================================
--- /Users/go/working_copies/django/django/template/loader_tags.py	(revision 6022)
+++ /Users/go/working_copies/django/django/template/loader_tags.py	(working copy)
@@ -1,6 +1,7 @@
 from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable
-from django.template import Library, Node
+from django.template import Library, Node, signals
 from django.template.loader import get_template, get_template_from_string, find_template_source
+from django.dispatch import dispatcher
 from django.conf import settings
 
 register = Library()
@@ -113,6 +114,44 @@
         except:
             return '' # Fail silently for invalid included templates.
 
+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 clear_template_include_cache():
+    RecursiveIncludeNode.cache = {}
+
+dispatcher.connect(clear_template_include_cache, signal=signals.request_finished)
+dispatcher.connect(clear_template_include_cache, signal=signals.got_request_exception)
+
 def do_block(parser, token):
     """
     Define a block that can be overridden by child templates.
@@ -171,7 +210,20 @@
     if path[0] in ('"', "'") and path[-1] == path[0]:
         return ConstantIncludeNode(path[1:-1])
     return IncludeNode(bits[1])
+    
+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('block', do_block)
 register.tag('extends', do_extends)
 register.tag('include', do_include)
+register.tag('rec_include', rec_include)
