Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[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
@freakboy3742 freakboy3742 authored
View
7 django/template/__init__.py
@@ -760,6 +760,7 @@ class Node(object):
# Set this to True for nodes that must be first in the template (although
# they can be preceded by text nodes.
must_be_first = False
+ child_nodelists = ('nodelist',)
def render(self, context):
"Return the node rendered as a string"
@@ -773,8 +774,10 @@ def get_nodes_by_type(self, nodetype):
nodes = []
if isinstance(self, nodetype):
nodes.append(self)
- if hasattr(self, 'nodelist'):
- nodes.extend(self.nodelist.get_nodes_by_type(nodetype))
+ for attr in self.child_nodelists:
+ nodelist = getattr(self, attr, None)
+ if nodelist:
+ nodes.extend(nodelist.get_nodes_by_type(nodetype))
return nodes
class NodeList(list):
View
24 django/template/defaulttags.py
@@ -85,6 +85,8 @@ def render(self, context):
return u''
class ForNode(Node):
+ child_nodelists = ('nodelist_loop', 'nodelist_empty')
+
def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None):
self.loopvars, self.sequence = loopvars, sequence
self.is_reversed = is_reversed
@@ -106,14 +108,6 @@ def __iter__(self):
for node in self.nodelist_empty:
yield node
- def get_nodes_by_type(self, nodetype):
- nodes = []
- if isinstance(self, nodetype):
- nodes.append(self)
- nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype))
- nodes.extend(self.nodelist_empty.get_nodes_by_type(nodetype))
- return nodes
-
def render(self, context):
if 'forloop' in context:
parentloop = context['forloop']
@@ -169,6 +163,8 @@ def render(self, context):
return nodelist.render(context)
class IfChangedNode(Node):
+ child_nodelists = ('nodelist_true', 'nodelist_false')
+
def __init__(self, nodelist_true, nodelist_false, *varlist):
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self._last_seen = None
@@ -199,6 +195,8 @@ def render(self, context):
return ''
class IfEqualNode(Node):
+ child_nodelists = ('nodelist_true', 'nodelist_false')
+
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
self.var1, self.var2 = var1, var2
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@@ -215,6 +213,8 @@ def render(self, context):
return self.nodelist_false.render(context)
class IfNode(Node):
+ child_nodelists = ('nodelist_true', 'nodelist_false')
+
def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
self.bool_exprs = bool_exprs
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@@ -229,14 +229,6 @@ def __iter__(self):
for node in self.nodelist_false:
yield node
- def get_nodes_by_type(self, nodetype):
- nodes = []
- if isinstance(self, nodetype):
- nodes.append(self)
- nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
- nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
- return nodes
-
def render(self, context):
if self.link_type == IfNode.LinkTypes.or_:
for ifnot, bool_expr in self.bool_exprs:
View
30 tests/regressiontests/templates/nodelist.py
@@ -0,0 +1,30 @@
+from unittest import TestCase
+from django.template.loader import get_template_from_string
+from django.template import VariableNode
+
+
+class NodelistTest(TestCase):
+
+ def test_for(self):
+ source = '{% for i in 1 %}{{ a }}{% endfor %}'
+ template = get_template_from_string(source)
+ vars = template.nodelist.get_nodes_by_type(VariableNode)
+ self.assertEqual(len(vars), 1)
+
+ def test_if(self):
+ source = '{% if x %}{{ a }}{% endif %}'
+ template = get_template_from_string(source)
+ vars = template.nodelist.get_nodes_by_type(VariableNode)
+ self.assertEqual(len(vars), 1)
+
+ def test_ifequal(self):
+ source = '{% ifequal x y %}{{ a }}{% endifequal %}'
+ template = get_template_from_string(source)
+ vars = template.nodelist.get_nodes_by_type(VariableNode)
+ self.assertEqual(len(vars), 1)
+
+ def test_ifchanged(self):
+ source = '{% ifchanged x %}{{ a }}{% endifchanged %}'
+ template = get_template_from_string(source)
+ vars = template.nodelist.get_nodes_by_type(VariableNode)
+ self.assertEqual(len(vars), 1)
View
27 tests/regressiontests/templates/tests.py
@@ -24,6 +24,7 @@
from custom import custom_filters
from parser import token_parsing, filter_parsing, variable_parsing
from unicode import unicode_tests
+from nodelist import NodelistTest
try:
from loaders import *
@@ -804,6 +805,32 @@ def get_template_tests(self):
# Inheritance from a template with a space in its name should work.
'inheritance29': ("{% extends 'inheritance 28' %}", {}, '!'),
+ # Base template, putting block in a conditional {% if %} tag
+ 'inheritance30': ("1{% if optional %}{% block opt %}2{% endblock %}{% endif %}3", {'optional': True}, '123'),
+
+ # Inherit from a template with block wrapped in an {% if %} tag (in parent), still gets overridden
+ 'inheritance31': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {'optional': True}, '1two3'),
+ 'inheritance32': ("{% extends 'inheritance30' %}{% block opt %}two{% endblock %}", {}, '13'),
+
+ # Base template, putting block in a conditional {% ifequal %} tag
+ 'inheritance33': ("1{% ifequal optional 1 %}{% block opt %}2{% endblock %}{% endifequal %}3", {'optional': 1}, '123'),
+
+ # Inherit from a template with block wrapped in an {% ifequal %} tag (in parent), still gets overridden
+ 'inheritance34': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 1}, '1two3'),
+ 'inheritance35': ("{% extends 'inheritance33' %}{% block opt %}two{% endblock %}", {'optional': 2}, '13'),
+
+ # Base template, putting block in a {% for %} tag
+ 'inheritance36': ("{% for n in numbers %}_{% block opt %}{{ n }}{% endblock %}{% endfor %}_", {'numbers': '123'}, '_1_2_3_'),
+
+ # Inherit from a template with block wrapped in an {% for %} tag (in parent), still gets overridden
+ 'inheritance37': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {'numbers': '123'}, '_X_X_X_'),
+ 'inheritance38': ("{% extends 'inheritance36' %}{% block opt %}X{% endblock %}", {}, '_'),
+
+ # The super block will still be found.
+ 'inheritance39': ("{% extends 'inheritance30' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': True}, '1new23'),
+ 'inheritance40': ("{% extends 'inheritance33' %}{% block opt %}new{{ block.super }}{% endblock %}", {'optional': 1}, '1new23'),
+ 'inheritance41': ("{% extends 'inheritance36' %}{% block opt %}new{{ block.super }}{% endblock %}", {'numbers': '123'}, '_new1_new2_new3_'),
+
### I18N ##################################################################
# {% spaceless %} tag

0 comments on commit 755a0f6

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