Fixed #6510 -- Refactored the way child nodes are found in template nodes 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
This commit is contained in:
parent
ecb56cecbd
commit
f034c79cbc
|
@ -770,6 +770,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"
|
||||
|
@ -783,8 +784,10 @@ class Node(object):
|
|||
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):
|
||||
|
|
|
@ -97,6 +97,8 @@ class FirstOfNode(Node):
|
|||
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
|
||||
|
@ -118,14 +120,6 @@ class ForNode(Node):
|
|||
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']
|
||||
|
@ -181,6 +175,8 @@ class ForNode(Node):
|
|||
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
|
||||
|
@ -211,6 +207,8 @@ class IfChangedNode(Node):
|
|||
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
|
||||
|
@ -227,6 +225,8 @@ class IfEqualNode(Node):
|
|||
return self.nodelist_false.render(context)
|
||||
|
||||
class IfNode(Node):
|
||||
child_nodelists = ('nodelist_true', 'nodelist_false')
|
||||
|
||||
def __init__(self, var, nodelist_true, nodelist_false=None):
|
||||
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
|
||||
self.var = var
|
||||
|
@ -240,14 +240,6 @@ class IfNode(Node):
|
|||
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.var.eval(context):
|
||||
return self.nodelist_true.render(context)
|
||||
|
|
|
@ -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)
|
|
@ -24,6 +24,7 @@ from context import context_tests
|
|||
from custom import custom_filters
|
||||
from parser import token_parsing, filter_parsing, variable_parsing
|
||||
from unicode import unicode_tests
|
||||
from nodelist import NodelistTest
|
||||
from smartif import *
|
||||
|
||||
try:
|
||||
|
@ -886,6 +887,32 @@ class Templates(unittest.TestCase):
|
|||
# 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
|
||||
|
|
Loading…
Reference in New Issue