diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index e6492dcd38..1f744f1958 100644 --- a/django/template/defaultfilters.py +++ b/django/template/defaultfilters.py @@ -651,7 +651,13 @@ unordered_list.needs_autoescape = True def add(value, arg): """Adds the arg to the value.""" - return int(value) + int(arg) + try: + return int(value) + int(arg) + except (ValueError, TypeError): + try: + return value + arg + except: + return value add.is_safe = False def get_digit(value, arg): diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index b9fa99bf6f..aabacc5650 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1010,6 +1010,27 @@ For example:: If ``value`` is ``4``, then the output will be ``6``. +.. versionchanged:: 1.2 + The following behavior didn't exist in previous Django versions. + +This filter will first try to coerce both values to integers. If this fails, +it'll attempt to add the values together anyway. This will work on some data +types (strings, list, etc.) and fail on others. If it fails, the result will +be an empty string. + +For example, if we have:: + + {{ first|add:second }} + +and ``first`` is ``[1, 2, 3]`` and ``second`` is ``[4, 5, 6]``, then the +output will be ``[1, 2, 3, 4, 5, 6]``. + +.. warning:: + + Keep in mind that strings that can both be coerced to integers will be, + and thus will be will be *summed*, not concatenated, as in the first + example above. + .. templatefilter:: addslashes addslashes diff --git a/tests/regressiontests/templates/filters.py b/tests/regressiontests/templates/filters.py index d2e8e7473b..c39e34b999 100644 --- a/tests/regressiontests/templates/filters.py +++ b/tests/regressiontests/templates/filters.py @@ -333,4 +333,15 @@ def get_filter_tests(): 'date02': (r'{{ d|date }}', {'d': datetime(2008, 1, 1)}, 'Jan. 1, 2008'), #Ticket 9520: Make sure |date doesn't blow up on non-dates 'date03': (r'{{ d|date:"m" }}', {'d': 'fail_string'}, ''), + + # base tests for add that assert, that old behaviour, which means + # trying to add two values as ints, is kept + 'add01': (r'{{ i|add:"5" }}', {'i': 2000}, '2005'), + 'add02': (r'{{ i|add:"napis" }}', {'i': 2000}, '2000'), + 'add03': (r'{{ i|add:16 }}', {'i': 'not_an_int'}, 'not_an_int'), + 'add04': (r'{{ i|add:"16" }}', {'i': 'not_an_int'}, 'not_an_int16'), + # further additions using dynamic typing + 'add05': (r'{{ l1|add:l2 }}', {'l1': [1, 2], 'l2': [3, 4]}, '[1, 2, 3, 4]'), + 'add06': (r'{{ t1|add:t2 }}', {'t1': (3, 4), 't2': (1, 2)}, '(3, 4, 1, 2)'), + 'add07': (r'{{ d|add:t }}', {'d': date(2000, 1, 1), 't': timedelta(10)}, '2000-01-11'), }