Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.1.X] Fixed #6510 -- Refactored the way child nodes are found in te…

…mplate nodes to avoid potential inconsistencies. Thanks to SmileyChris for the patch.

Backport of r12654 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@12655 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 755a0f6d96573ae5ccc2e2693e630c63c75a06ea 1 parent a622539
Russell Keith-Magee authored March 02, 2010
7  django/template/__init__.py
@@ -760,6 +760,7 @@ class Node(object):
760 760
     # Set this to True for nodes that must be first in the template (although
761 761
     # they can be preceded by text nodes.
762 762
     must_be_first = False
  763
+    child_nodelists = ('nodelist',)
763 764
 
764 765
     def render(self, context):
765 766
         "Return the node rendered as a string"
@@ -773,8 +774,10 @@ def get_nodes_by_type(self, nodetype):
773 774
         nodes = []
774 775
         if isinstance(self, nodetype):
775 776
             nodes.append(self)
776  
-        if hasattr(self, 'nodelist'):
777  
-            nodes.extend(self.nodelist.get_nodes_by_type(nodetype))
  777
+        for attr in self.child_nodelists:
  778
+            nodelist = getattr(self, attr, None)
  779
+            if nodelist:
  780
+                nodes.extend(nodelist.get_nodes_by_type(nodetype))
778 781
         return nodes
779 782
 
780 783
 class NodeList(list):
24  django/template/defaulttags.py
@@ -85,6 +85,8 @@ def render(self, context):
85 85
         return u''
86 86
 
87 87
 class ForNode(Node):
  88
+    child_nodelists = ('nodelist_loop', 'nodelist_empty')
  89
+
88 90
     def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None):
89 91
         self.loopvars, self.sequence = loopvars, sequence
90 92
         self.is_reversed = is_reversed
@@ -106,14 +108,6 @@ def __iter__(self):
106 108
         for node in self.nodelist_empty:
107 109
             yield node
108 110
 
109  
-    def get_nodes_by_type(self, nodetype):
110  
-        nodes = []
111  
-        if isinstance(self, nodetype):
112  
-            nodes.append(self)
113  
-        nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype))
114  
-        nodes.extend(self.nodelist_empty.get_nodes_by_type(nodetype))
115  
-        return nodes
116  
-
117 111
     def render(self, context):
118 112
         if 'forloop' in context:
119 113
             parentloop = context['forloop']
@@ -169,6 +163,8 @@ def render(self, context):
169 163
         return nodelist.render(context)
170 164
 
171 165
 class IfChangedNode(Node):
  166
+    child_nodelists = ('nodelist_true', 'nodelist_false')
  167
+
172 168
     def __init__(self, nodelist_true, nodelist_false, *varlist):
173 169
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
174 170
         self._last_seen = None
@@ -199,6 +195,8 @@ def render(self, context):
199 195
         return ''
200 196
 
201 197
 class IfEqualNode(Node):
  198
+    child_nodelists = ('nodelist_true', 'nodelist_false')
  199
+
202 200
     def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
203 201
         self.var1, self.var2 = var1, var2
204 202
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@@ -215,6 +213,8 @@ def render(self, context):
215 213
         return self.nodelist_false.render(context)
216 214
 
217 215
 class IfNode(Node):
  216
+    child_nodelists = ('nodelist_true', 'nodelist_false')
  217
+
218 218
     def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
219 219
         self.bool_exprs = bool_exprs
220 220
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@@ -229,14 +229,6 @@ def __iter__(self):
229 229
         for node in self.nodelist_false:
230 230
             yield node
231 231
 
232  
-    def get_nodes_by_type(self, nodetype):
233  
-        nodes = []
234  
-        if isinstance(self, nodetype):
235  
-            nodes.append(self)
236  
-        nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
237  
-        nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
238  
-        return nodes
239  
-
240 232
     def render(self, context):
241 233
         if self.link_type == IfNode.LinkTypes.or_:
242 234
             for ifnot, bool_expr in self.bool_exprs:
30  tests/regressiontests/templates/nodelist.py
... ...
@@ -0,0 +1,30 @@
  1
+from unittest import TestCase
  2
+from django.template.loader import get_template_from_string
  3
+from django.template import VariableNode
  4
+
  5
+
  6
+class NodelistTest(TestCase):
  7
+
  8
+    def test_for(self):
  9
+        source = '{% for i in 1 %}{{ a }}{% endfor %}'
  10
+        template = get_template_from_string(source)
  11
+        vars = template.nodelist.get_nodes_by_type(VariableNode)
  12
+        self.assertEqual(len(vars), 1)
  13
+
  14
+    def test_if(self):
  15
+        source = '{% if x %}{{ a }}{% endif %}'
  16
+        template = get_template_from_string(source)
  17
+        vars = template.nodelist.get_nodes_by_type(VariableNode)
  18
+        self.assertEqual(len(vars), 1)
  19
+
  20
+    def test_ifequal(self):
  21
+        source = '{% ifequal x y %}{{ a }}{% endifequal %}'
  22
+        template = get_template_from_string(source)
  23
+        vars = template.nodelist.get_nodes_by_type(VariableNode)
  24
+        self.assertEqual(len(vars), 1)
  25
+
  26
+    def test_ifchanged(self):
  27
+        source = '{% ifchanged x %}{{ a }}{% endifchanged %}'
  28
+        template = get_template_from_string(source)
  29
+        vars = template.nodelist.get_nodes_by_type(VariableNode)
  30
+        self.assertEqual(len(vars), 1)
27  tests/regressiontests/templates/tests.py
@@ -24,6 +24,7 @@
24 24
 from custom import custom_filters
25 25
 from parser import token_parsing, filter_parsing, variable_parsing
26 26
 from unicode import unicode_tests
  27
+from nodelist import NodelistTest
27 28
 
28 29
 try:
29 30
     from loaders import *
@@ -804,6 +805,32 @@ def get_template_tests(self):
804 805
             # Inheritance from a template with a space in its name should work.
805 806
             'inheritance29': ("{% extends 'inheritance 28' %}", {}, '!'),
806 807
 
  808
+            # Base template, putting block in a conditional {% if %} tag
  809
+            'inheritance30': ("1{% if optional %}{% block opt %}2{% endblock %}{% endif %}3", {'optional': True}, '123'),
  810
+
  811
+            # Inherit from a template with block wrapped in an {% if %} tag (in parent), still gets overridden
  812
+            'inheritance31': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {'optional': True}, '1two3'),
  813
+            'inheritance32': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {}, '13'),
  814
+
  815
+            # Base template, putting block in a conditional {% ifequal %} tag
  816
+            'inheritance33': ("1{% ifequal optional 1 %}{% block opt %}2{% endblock %}{% endifequal %}3", {'optional': 1}, '123'),
  817
+
  818
+            # Inherit from a template with block wrapped in an {% ifequal %} tag (in parent), still gets overridden
  819
+            'inheritance34': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 1}, '1two3'),
  820
+            'inheritance35': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 2}, '13'),
  821
+
  822
+            # Base template, putting block in a {% for %} tag
  823
+            'inheritance36': ("{% for n in numbers %}_{% block opt %}{{ n }}{% endblock %}{% endfor %}_", {'numbers': '123'}, '_1_2_3_'),
  824
+
  825
+            # Inherit from a template with block wrapped in an {% for %} tag (in parent), still gets overridden
  826
+            'inheritance37': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {'numbers': '123'}, '_X_X_X_'),
  827
+            'inheritance38': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {}, '_'),
  828
+
  829
+            # The super block will still be found.
  830
+            'inheritance39': ("{% extends 'inheritance30' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': True}, '1new23'),
  831
+            'inheritance40': ("{% extends 'inheritance33' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': 1}, '1new23'),
  832
+            'inheritance41': ("{% extends 'inheritance36' %}{% block opt %}new{{ block.super }}{% endblock %}", {'numbers': '123'}, '_new1_new2_new3_'),
  833
+
807 834
             ### I18N ##################################################################
808 835
 
809 836
             # {% spaceless %} tag

0 notes on commit 755a0f6

Please sign in to comment.
Something went wrong with that request. Please try again.