Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Make templates more reusable by Improving template loading algorithm to avoid extending infinite recursion #217

Closed
wants to merge 8 commits into from

5 participants

Pablo Martín Florian Apolloner Leo Trubach yed podtrzitko Anssi Kääriäinen
Anssi Kääriäinen

Please remove...

This was removed in this commit (2 minutes after) bf23921

yed podtrzitko

What is this if-else for, when it contains the same code?

Probably LoaderOriginLite should be in the second line

This a intermediate step. Please, see the final diff:

https://github.com/django/django/pull/217/files#L2R81

Pablo Martín
goinnn commented July 24, 2012

didn't I convince you? :-( Tell me something

Florian Apolloner
Owner

@goinnn as @akaariai noted on the ticket this patch needs tests and docs! (And yes I'd really like to see this feature in core :))

Pablo Martín

Hi @apollo13. I'm sorry but I was trying for two years to add this feature. I'm bored to try it. If you can get it. Congratulantions!

Florian Apolloner
Owner

Ok, closing for now then. If someone else wants to work on it please open a new pull request for review.

Florian Apolloner apollo13 closed this January 02, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
6  django/template/base.py
@@ -227,9 +227,14 @@ def create_token(self, token_string, in_tag):
227 227
         else:
228 228
             token = Token(TOKEN_TEXT, token_string)
229 229
         token.lineno = self.lineno
  230
+        # token.source is a tuple, this contains origin object and
  231
+        # the range of the columns where is this token.
  232
+        # If TEMPLATE_DEBUG = False we don't need it, therefore we set with (-1, -1)
  233
+        token.source = self.origin, (-1, -1) 
230 234
         self.lineno += token_string.count('\n')
231 235
         return token
232 236
 
  237
+
233 238
 class Parser(object):
234 239
     def __init__(self, tokens):
235 240
         self.tokens = tokens
@@ -304,6 +309,7 @@ def extend_nodelist(self, nodelist, node, token):
304 309
                                           "in the template." % node)
305 310
         if isinstance(nodelist, NodeList) and not isinstance(node, TextNode):
306 311
             nodelist.contains_nontext = True
  312
+        node.source = token.source
307 313
         nodelist.append(node)
308 314
 
309 315
     def enter_command(self, command, token):
4  django/template/debug.py
@@ -55,10 +55,6 @@ def create_nodelist(self):
55 55
     def create_variable_node(self, contents):
56 56
         return DebugVariableNode(contents)
57 57
 
58  
-    def extend_nodelist(self, nodelist, node, token):
59  
-        node.source = token.source
60  
-        super(DebugParser, self).extend_nodelist(nodelist, node, token)
61  
-
62 58
     def unclosed_block_tag(self, parse_until):
63 59
         command, source = self.command_stack.pop()
64 60
         msg = "Unclosed tag '%s'. Looking for one of: %s " % (command, ', '.join(parse_until))
32  django/template/loader.py
@@ -79,10 +79,9 @@ def reload(self):
79 79
         return self.loader(self.loadname, self.dirs)[0]
80 80
 
81 81
 def make_origin(display_name, loader, name, dirs):
82  
-    if settings.TEMPLATE_DEBUG and display_name:
  82
+    if display_name:
83 83
         return LoaderOrigin(display_name, loader, name, dirs)
84  
-    else:
85  
-        return None
  84
+    return None
86 85
 
87 86
 def find_template_loader(loader):
88 87
     if isinstance(loader, (tuple, list)):
@@ -117,7 +116,12 @@ def find_template_loader(loader):
117 116
     else:
118 117
         raise ImproperlyConfigured('Loader does not define a "load_template" callable template source loader')
119 118
 
120  
-def find_template(name, dirs=None):
  119
+def find_template(name, dirs=None, skip_template=None):
  120
+    """
  121
+    Returns a tuple with a compiled Template object for the given template name,
  122
+    and a origin object. Skipping the current template (skip_template),
  123
+    this param contain the absolute path of the template.
  124
+    """
121 125
     # Calculate template_source_loaders the first time the function is executed
122 126
     # because putting this logic in the module-level namespace may cause
123 127
     # circular import errors. See Django ticket #1292.
@@ -129,20 +133,32 @@ def find_template(name, dirs=None):
129 133
             if loader is not None:
130 134
                 loaders.append(loader)
131 135
         template_source_loaders = tuple(loaders)
  136
+    template_candidate = None
132 137
     for loader in template_source_loaders:
133 138
         try:
134 139
             source, display_name = loader(name, dirs)
135  
-            return (source, make_origin(display_name, loader, name, dirs))
  140
+            if skip_template and skip_template.endswith(name):
  141
+                extends_tags = source.nodelist[0]
  142
+                extends_tags_origin, extends_tags_source = extends_tags.source
  143
+                if extends_tags_origin.name == skip_template:
  144
+                    template_candidate = None
  145
+                    continue
  146
+                if not template_candidate:
  147
+                    template_candidate = (source, make_origin(display_name, loader, name, dirs))
  148
+            else:
  149
+                return (source, make_origin(display_name, loader, name, dirs))
136 150
         except TemplateDoesNotExist:
137 151
             pass
138  
-    raise TemplateDoesNotExist(name)
  152
+    if not template_candidate:
  153
+        raise TemplateDoesNotExist(name)
  154
+    return template_candidate
139 155
 
140  
-def get_template(template_name):
  156
+def get_template(template_name, skip_template=None):
141 157
     """
142 158
     Returns a compiled Template object for the given template name,
143 159
     handling template inheritance recursively.
144 160
     """
145  
-    template, origin = find_template(template_name)
  161
+    template, origin = find_template(template_name, skip_template=skip_template)
146 162
     if not hasattr(template, 'render'):
147 163
         # template needs to be compiled
148 164
         template = get_template_from_string(template, origin, template_name)
5  django/template/loader_tags.py
@@ -94,8 +94,9 @@ def get_parent(self, context):
94 94
                     self.parent_name.token
95 95
             raise TemplateSyntaxError(error_msg)
96 96
         if hasattr(parent, 'render'):
97  
-            return parent # parent is a Template object
98  
-        return get_template(parent)
  97
+            return parent  # parent is a Template object
  98
+        origin, source = self.source
  99
+        return get_template(parent, skip_template=origin.name)
99 100
 
100 101
     def render(self, context):
101 102
         compiled_parent = self.get_parent(context)
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.