Index: django/template/loader_tags.py
===================================================================
--- django/template/loader_tags.py	(revisión: 10558)
+++ django/template/loader_tags.py	(copia de trabajo)
@@ -1,6 +1,6 @@
 from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
-from django.template import Library, Node, TextNode
-from django.template.loader import get_template, get_template_from_string, find_template_source
+from django.template import Library, Node, NodeList, TextNode
+from django.template.loader import get_template
 from django.conf import settings
 from django.utils.safestring import mark_safe
 
@@ -43,6 +43,10 @@
         self.nodelist = nodelist
         self.parent_name, self.parent_name_expr = parent_name, parent_name_expr
         self.template_dirs = template_dirs
+        if self.parent_name_expr is None:
+            self.compiled_parent = self.get_parent(context=None)
+        else:
+            self.compiled_parent = None
 
     def __repr__(self):
         if self.parent_name_expr:
@@ -61,15 +65,18 @@
         if hasattr(parent, 'render'):
             return parent # parent is a Template object
         try:
-            source, origin = find_template_source(parent, self.template_dirs)
+            return get_template(parent, self.template_dirs)
         except TemplateDoesNotExist:
             raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
-        else:
-            return get_template_from_string(source, origin, parent)
 
     def render(self, context):
-        compiled_parent = self.get_parent(context)
+        if self.compiled_parent is not None:
+            compiled_parent = self.compiled_parent
+        else:
+            compiled_parent = self.get_parent(context)
         parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
+        old_parent_nodelists = {}
+        added_extended_blocknodes = []
         for block_node in self.nodelist.get_nodes_by_type(BlockNode):
             # Check for a BlockNode with this node's name, and replace it if found.
             try:
@@ -86,6 +93,7 @@
                         # If the first non-text node is an extends, handle it.
                         if isinstance(node, ExtendsNode):
                             node.nodelist.append(block_node)
+                            added_extended_blocknodes.append(block_node.name)
                         # Extends must be the first non-text node, so once you find
                         # the first non-text node you can stop looking. 
                         break
@@ -93,8 +101,19 @@
                 # Keep any existing parents and add a new one. Used by BlockNode.
                 parent_block.parent = block_node.parent
                 parent_block.add_parent(parent_block.nodelist)
+                old_parent_nodelists[block_node.name] = parent_block.nodelist
                 parent_block.nodelist = block_node.nodelist
-        return compiled_parent.render(context)
+        rendered_string = compiled_parent.render(context)
+        # Restore every original parent nodelist to the state prior rendering it
+        for node_name, nodelist in old_parent_nodelists.items():
+            parent_blocks[node_name].nodelist = nodelist
+        # Remove added BlockNodes to the parent's ExtendsNode
+        for node in compiled_parent.nodelist:
+            if not isinstance(node, TextNode):
+                if isinstance(node, ExtendsNode):
+                    node.nodelist = NodeList(filter(lambda n: not isinstance(n, BlockNode) or n.name not in added_extended_blocknodes, node.nodelist))
+                break
+        return rendered_string
 
 class ConstantIncludeNode(Node):
     def __init__(self, template_path):
@@ -156,7 +175,7 @@
     uses the literal value "base" as the name of the parent template to extend,
     or ``{% extends variable %}`` uses the value of ``variable`` as either the
     name of the parent template to extend (if it evaluates to a string) or as
-    the parent tempate itelf (if it evaluates to a Template object).
+    the parent template itself (if it evaluates to a Template object).
     """
     bits = token.split_contents()
     if len(bits) != 2:
Index: django/template/loader.py
===================================================================
--- django/template/loader.py	(revisión: 10558)
+++ django/template/loader.py	(copia de trabajo)
@@ -27,6 +27,8 @@
 
 template_source_loaders = None
 
+_template_cache = {}
+
 class LoaderOrigin(Origin):
     def __init__(self, display_name, loader, name, dirs):
         super(LoaderOrigin, self).__init__(display_name)
@@ -73,13 +75,17 @@
             pass
     raise TemplateDoesNotExist, name
 
-def get_template(template_name):
+def get_template(template_name, dirs=None):
     """
     Returns a compiled Template object for the given template name,
     handling template inheritance recursively.
     """
-    source, origin = find_template_source(template_name)
-    template = get_template_from_string(source, origin, template_name)
+    if not settings.TEMPLATE_DEBUG and template_name in _template_cache:
+        template = _template_cache[template_name]
+    else:
+        source, origin = find_template_source(template_name, dirs)
+        template = get_template_from_string(source, origin, template_name)
+        _template_cache[template_name] = template
     return template
 
 def get_template_from_string(source, origin=None, name=None):
