Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #6510 -- Refactored the way child nodes are found in template n…

…odes to avoid potential inconsistencies. Thanks to SmileyChris for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12654 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f034c79cbc4f1a235e53d4ec666885ab8e9af8d9 1 parent ecb56ce
Russell Keith-Magee authored March 02, 2010
7  django/template/__init__.py
@@ -770,6 +770,7 @@ class Node(object):
770 770
     # Set this to True for nodes that must be first in the template (although
771 771
     # they can be preceded by text nodes.
772 772
     must_be_first = False
  773
+    child_nodelists = ('nodelist',)
773 774
 
774 775
     def render(self, context):
775 776
         "Return the node rendered as a string"
@@ -783,8 +784,10 @@ def get_nodes_by_type(self, nodetype):
783 784
         nodes = []
784 785
         if isinstance(self, nodetype):
785 786
             nodes.append(self)
786  
-        if hasattr(self, 'nodelist'):
787  
-            nodes.extend(self.nodelist.get_nodes_by_type(nodetype))
  787
+        for attr in self.child_nodelists:
  788
+            nodelist = getattr(self, attr, None)
  789
+            if nodelist:
  790
+                nodes.extend(nodelist.get_nodes_by_type(nodetype))
788 791
         return nodes
789 792
 
790 793
 class NodeList(list):
24  django/template/defaulttags.py
@@ -97,6 +97,8 @@ def render(self, context):
97 97
         return u''
98 98
 
99 99
 class ForNode(Node):
  100
+    child_nodelists = ('nodelist_loop', 'nodelist_empty')
  101
+
100 102
     def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None):
101 103
         self.loopvars, self.sequence = loopvars, sequence
102 104
         self.is_reversed = is_reversed
@@ -118,14 +120,6 @@ def __iter__(self):
118 120
         for node in self.nodelist_empty:
119 121
             yield node
120 122
 
121  
-    def get_nodes_by_type(self, nodetype):
122  
-        nodes = []
123  
-        if isinstance(self, nodetype):
124  
-            nodes.append(self)
125  
-        nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype))
126  
-        nodes.extend(self.nodelist_empty.get_nodes_by_type(nodetype))
127  
-        return nodes
128  
-
129 123
     def render(self, context):
130 124
         if 'forloop' in context:
131 125
             parentloop = context['forloop']
@@ -181,6 +175,8 @@ def render(self, context):
181 175
         return nodelist.render(context)
182 176
 
183 177
 class IfChangedNode(Node):
  178
+    child_nodelists = ('nodelist_true', 'nodelist_false')
  179
+
184 180
     def __init__(self, nodelist_true, nodelist_false, *varlist):
185 181
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
186 182
         self._last_seen = None
@@ -211,6 +207,8 @@ def render(self, context):
211 207
         return ''
212 208
 
213 209
 class IfEqualNode(Node):
  210
+    child_nodelists = ('nodelist_true', 'nodelist_false')
  211
+
214 212
     def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
215 213
         self.var1, self.var2 = var1, var2
216 214
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@@ -227,6 +225,8 @@ def render(self, context):
227 225
         return self.nodelist_false.render(context)
228 226
 
229 227
 class IfNode(Node):
  228
+    child_nodelists = ('nodelist_true', 'nodelist_false')
  229
+
230 230
     def __init__(self, var, nodelist_true, nodelist_false=None):
231 231
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
232 232
         self.var = var
@@ -240,14 +240,6 @@ def __iter__(self):
240 240
         for node in self.nodelist_false:
241 241
             yield node
242 242
 
243  
-    def get_nodes_by_type(self, nodetype):
244  
-        nodes = []
245  
-        if isinstance(self, nodetype):
246  
-            nodes.append(self)
247  
-        nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
248  
-        nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
249  
-        return nodes
250  
-
251 243
     def render(self, context):
252 244
         if self.var.eval(context):
253 245
             return self.nodelist_true.render(context)
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
 from smartif import *
28 29
 
29 30
 try:
@@ -886,6 +887,32 @@ def get_template_tests(self):
886 887
             # Inheritance from a template with a space in its name should work.
887 888
             'inheritance29': ("{% extends 'inheritance 28' %}", {}, '!'),
888 889
 
  890
+            # Base template, putting block in a conditional {% if %} tag
  891
+            'inheritance30': ("1{% if optional %}{% block opt %}2{% endblock %}{% endif %}3", {'optional': True}, '123'),
  892
+
  893
+            # Inherit from a template with block wrapped in an {% if %} tag (in parent), still gets overridden
  894
+            'inheritance31': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {'optional': True}, '1two3'),
  895
+            'inheritance32': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {}, '13'),
  896
+
  897
+            # Base template, putting block in a conditional {% ifequal %} tag
  898
+            'inheritance33': ("1{% ifequal optional 1 %}{% block opt %}2{% endblock %}{% endifequal %}3", {'optional': 1}, '123'),
  899
+
  900
+            # Inherit from a template with block wrapped in an {% ifequal %} tag (in parent), still gets overridden
  901
+            'inheritance34': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 1}, '1two3'),
  902
+            'inheritance35': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 2}, '13'),
  903
+
  904
+            # Base template, putting block in a {% for %} tag
  905
+            'inheritance36': ("{% for n in numbers %}_{% block opt %}{{ n }}{% endblock %}{% endfor %}_", {'numbers': '123'}, '_1_2_3_'),
  906
+
  907
+            # Inherit from a template with block wrapped in an {% for %} tag (in parent), still gets overridden
  908
+            'inheritance37': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {'numbers': '123'}, '_X_X_X_'),
  909
+            'inheritance38': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {}, '_'),
  910
+
  911
+            # The super block will still be found.
  912
+            'inheritance39': ("{% extends 'inheritance30' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': True}, '1new23'),
  913
+            'inheritance40': ("{% extends 'inheritance33' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': 1}, '1new23'),
  914
+            'inheritance41': ("{% extends 'inheritance36' %}{% block opt %}new{{ block.super }}{% endblock %}", {'numbers': '123'}, '_new1_new2_new3_'),
  915
+
889 916
             ### I18N ##################################################################
890 917
 
891 918
             # {% spaceless %} tag

0 notes on commit f034c79

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