diff --git a/django/template/__init__.py b/django/template/__init__.py index 08f433fec9..993de7304e 100644 --- a/django/template/__init__.py +++ b/django/template/__init__.py @@ -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: diff --git a/django/template/context.py b/django/template/context.py index 44a97f95a8..6d9efdc7ec 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -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] diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 88cb5f68be..0a4fe33d82 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -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 "" 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)): diff --git a/tests/othertests/templates.py b/tests/othertests/templates.py index c0333c90a6..d3b09c5310 100644 --- a/tests/othertests/templates.py +++ b/tests/othertests/templates.py @@ -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