diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index bc78542184..71e5bd61ea 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -476,7 +476,7 @@ length.is_safe = True def length_is(value, arg): """Returns a boolean of whether the value's length is the argument.""" return len(value) == int(arg) -length_is.is_safe = True +length_is.is_safe = False def random(value): """Returns a random item from the list.""" diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt index 8923cbbb13..b680272f40 100644 --- a/docs/howto/custom-template-tags.txt +++ b/docs/howto/custom-template-tags.txt @@ -241,6 +241,12 @@ Template filter code falls into one of two situations: this tricky, but keep an eye out for any problems like that when reviewing your code. + Marking a filter ``is_safe`` will coerce the filter's return value to + a string. If your filter should return a boolean or other non-string + value, marking it ``is_safe`` will probably have unintended + consequences (such as converting a boolean False to the string + 'False'). + 2. Alternatively, your filter code can manually take care of any necessary escaping. This is necessary when you're introducing new HTML markup into the result. You want to mark the output as safe from further diff --git a/tests/regressiontests/templates/filters.py b/tests/regressiontests/templates/filters.py index bee568698c..d69a885822 100644 --- a/tests/regressiontests/templates/filters.py +++ b/tests/regressiontests/templates/filters.py @@ -277,5 +277,9 @@ def get_filter_tests(): 'escapejs01': (r'{{ a|escapejs }}', {'a': 'testing\r\njavascript \'string" escaping'}, 'testing\\x0D\\x0Ajavascript \\x27string\\x22 \\x3Cb\\x3Eescaping\\x3C/b\\x3E'), 'escapejs02': (r'{% autoescape off %}{{ a|escapejs }}{% endautoescape %}', {'a': 'testing\r\njavascript \'string" escaping'}, 'testing\\x0D\\x0Ajavascript \\x27string\\x22 \\x3Cb\\x3Eescaping\\x3C/b\\x3E'), + + # Boolean return value from length_is should not be coerced to a string + 'lengthis01': (r'{% if "X"|length_is:0 %}Length is 0{% else %}Length not 0{% endif %}', {}, 'Length not 0'), + 'lengthis02': (r'{% if "X"|length_is:1 %}Length is 1{% else %}Length not 1{% endif %}', {}, 'Length is 1'), }