Fixes #1338, Refs #1400, #2237 -- Modified variable resolution to allow template 'if' statements to work if TEMPLATE_STRING_IF_INVALID is set. Modified unit tests to force the use of this variable, so that returning '' isn't confused with an actual failure.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@3268 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
009f224e57
commit
6b383afd39
|
@ -318,7 +318,7 @@ class Parser(object):
|
|||
self.tags.update(lib.tags)
|
||||
self.filters.update(lib.filters)
|
||||
|
||||
def compile_filter(self,token):
|
||||
def compile_filter(self, token):
|
||||
"Convenient wrapper for FilterExpression"
|
||||
return FilterExpression(token, self)
|
||||
|
||||
|
@ -543,11 +543,14 @@ class FilterExpression(object):
|
|||
raise TemplateSyntaxError, "Could not parse the remainder: %s" % token[upto:]
|
||||
self.var, self.filters = var, filters
|
||||
|
||||
def resolve(self, context):
|
||||
def resolve(self, context, ignore_failures=False):
|
||||
try:
|
||||
obj = resolve_variable(self.var, context)
|
||||
except VariableDoesNotExist:
|
||||
obj = settings.TEMPLATE_STRING_IF_INVALID
|
||||
if ignore_failures:
|
||||
return None
|
||||
else:
|
||||
return settings.TEMPLATE_STRING_IF_INVALID
|
||||
for func, args in self.filters:
|
||||
arg_vals = []
|
||||
for lookup, arg in args:
|
||||
|
|
|
@ -37,7 +37,7 @@ class Context(object):
|
|||
for d in self.dicts:
|
||||
if d.has_key(key):
|
||||
return d[key]
|
||||
return settings.TEMPLATE_STRING_IF_INVALID
|
||||
raise KeyError(key)
|
||||
|
||||
def __delitem__(self, key):
|
||||
"Delete a variable from the current context"
|
||||
|
@ -49,7 +49,7 @@ class Context(object):
|
|||
return True
|
||||
return False
|
||||
|
||||
def get(self, key, otherwise):
|
||||
def get(self, key, otherwise=None):
|
||||
for d in self.dicts:
|
||||
if d.has_key(key):
|
||||
return d[key]
|
||||
|
|
|
@ -45,7 +45,10 @@ class FirstOfNode(Node):
|
|||
|
||||
def render(self, context):
|
||||
for var in self.vars:
|
||||
value = resolve_variable(var, context)
|
||||
try:
|
||||
value = resolve_variable(var, context)
|
||||
except VariableDoesNotExist:
|
||||
continue
|
||||
if value:
|
||||
return str(value)
|
||||
return ''
|
||||
|
@ -144,8 +147,14 @@ class IfEqualNode(Node):
|
|||
return "<IfEqualNode>"
|
||||
|
||||
def render(self, context):
|
||||
val1 = resolve_variable(self.var1, context)
|
||||
val2 = resolve_variable(self.var2, context)
|
||||
try:
|
||||
val1 = resolve_variable(self.var1, context)
|
||||
except VariableDoesNotExist:
|
||||
val1 = None
|
||||
try:
|
||||
val2 = resolve_variable(self.var2, context)
|
||||
except VariableDoesNotExist:
|
||||
val2 = None
|
||||
if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
|
||||
return self.nodelist_true.render(context)
|
||||
return self.nodelist_false.render(context)
|
||||
|
@ -177,7 +186,7 @@ class IfNode(Node):
|
|||
if self.link_type == IfNode.LinkTypes.or_:
|
||||
for ifnot, bool_expr in self.bool_exprs:
|
||||
try:
|
||||
value = bool_expr.resolve(context)
|
||||
value = bool_expr.resolve(context, True)
|
||||
except VariableDoesNotExist:
|
||||
value = None
|
||||
if (value and not ifnot) or (ifnot and not value):
|
||||
|
@ -186,7 +195,7 @@ class IfNode(Node):
|
|||
else:
|
||||
for ifnot, bool_expr in self.bool_exprs:
|
||||
try:
|
||||
value = bool_expr.resolve(context)
|
||||
value = bool_expr.resolve(context, True)
|
||||
except VariableDoesNotExist:
|
||||
value = None
|
||||
if not ((value and not ifnot) or (ifnot and not value)):
|
||||
|
|
|
@ -78,7 +78,7 @@ TEMPLATE_TESTS = {
|
|||
'basic-syntax03': ("{{ first }} --- {{ second }}", {"first" : 1, "second" : 2}, "1 --- 2"),
|
||||
|
||||
# Fail silently when a variable is not found in the current context
|
||||
'basic-syntax04': ("as{{ missing }}df", {}, "asdf"),
|
||||
'basic-syntax04': ("as{{ missing }}df", {}, "asINVALIDdf"),
|
||||
|
||||
# A variable may not contain more than one word
|
||||
'basic-syntax06': ("{{ multi word variable }}", {}, template.TemplateSyntaxError),
|
||||
|
@ -94,7 +94,7 @@ TEMPLATE_TESTS = {
|
|||
'basic-syntax10': ("{{ var.otherclass.method }}", {"var": SomeClass()}, "OtherClass.method"),
|
||||
|
||||
# Fail silently when a variable's attribute isn't found
|
||||
'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, ""),
|
||||
'basic-syntax11': ("{{ var.blech }}", {"var": SomeClass()}, "INVALID"),
|
||||
|
||||
# Raise TemplateSyntaxError when trying to access a variable beginning with an underscore
|
||||
'basic-syntax12': ("{{ var.__dict__ }}", {"var": SomeClass()}, template.TemplateSyntaxError),
|
||||
|
@ -110,10 +110,10 @@ TEMPLATE_TESTS = {
|
|||
'basic-syntax18': ("{{ foo.bar }}", {"foo" : {"bar" : "baz"}}, "baz"),
|
||||
|
||||
# Fail silently when a variable's dictionary key isn't found
|
||||
'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, ""),
|
||||
'basic-syntax19': ("{{ foo.spam }}", {"foo" : {"bar" : "baz"}}, "INVALID"),
|
||||
|
||||
# Fail silently when accessing a non-simple method
|
||||
'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ""),
|
||||
'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, "INVALID"),
|
||||
|
||||
# Basic filter usage
|
||||
'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"),
|
||||
|
@ -152,7 +152,7 @@ TEMPLATE_TESTS = {
|
|||
'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'),
|
||||
|
||||
# Fail silently for methods that raise an exception with a "silent_variable_failure" attribute
|
||||
'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "12"),
|
||||
'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, "1INVALID2"),
|
||||
|
||||
# In methods that raise an exception without a "silent_variable_attribute" set to True,
|
||||
# the exception propogates
|
||||
|
@ -495,7 +495,7 @@ TEMPLATE_TESTS = {
|
|||
'{{ item.foo }}' + \
|
||||
'{% endfor %},' + \
|
||||
'{% endfor %}',
|
||||
{}, ''),
|
||||
{}, 'INVALID:INVALIDINVALIDINVALIDINVALIDINVALIDINVALIDINVALID,'),
|
||||
|
||||
### TEMPLATETAG TAG #######################################################
|
||||
'templatetag01': ('{% templatetag openblock %}', {}, '{%'),
|
||||
|
@ -579,6 +579,9 @@ def run_tests(verbosity=0, standalone=False):
|
|||
|
||||
# Turn TEMPLATE_DEBUG off, because tests assume that.
|
||||
old_td, settings.TEMPLATE_DEBUG = settings.TEMPLATE_DEBUG, False
|
||||
# Set TEMPLATE_STRING_IF_INVALID to a known string
|
||||
old_invalid, settings.TEMPLATE_STRING_IF_INVALID = settings.TEMPLATE_STRING_IF_INVALID, 'INVALID'
|
||||
|
||||
for name, vals in tests:
|
||||
install()
|
||||
if 'LANGUAGE_CODE' in vals[1]:
|
||||
|
@ -609,6 +612,7 @@ def run_tests(verbosity=0, standalone=False):
|
|||
loader.template_source_loaders = old_template_loaders
|
||||
deactivate()
|
||||
settings.TEMPLATE_DEBUG = old_td
|
||||
settings.TEMPLATE_STRING_IF_INVALID = old_invalid
|
||||
|
||||
if failed_tests and not standalone:
|
||||
msg = "Template tests %s failed." % failed_tests
|
||||
|
|
Loading…
Reference in New Issue