Loading django/utils/html.py +31 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,37 @@ def conditional_escape(text): else: return escape(text) def format_html(format_string, *args, **kwargs): """ Similar to str.format, but passes all arguments through conditional_escape, and calls 'mark_safe' on the result. This function should be used instead of str.format or % interpolation to build up small HTML fragments. """ args_safe = map(conditional_escape, args) kwargs_safe = dict([(k, conditional_escape(v)) for (k, v) in kwargs.iteritems()]) return mark_safe(format_string.format(*args_safe, **kwargs_safe)) def format_html_join(sep, format_string, args_generator): """ A wrapper format_html, for the common case of a group of arguments that need to be formatted using the same format string, and then joined using 'sep'. 'sep' is also passed through conditional_escape. 'args_generator' should be an iterator that returns the sequence of 'args' that will be passed to format_html. Example: format_html_join('\n', "<li>{0} {1}</li>", ((u.first_name, u.last_name) for u in users)) """ return mark_safe(conditional_escape(sep).join( format_html(format_string, *tuple(args)) for args in args_generator)) def linebreaks(value, autoescape=False): """Converts newlines into <p> and <br />s.""" value = normalize_newlines(value) Loading docs/ref/utils.txt +39 −0 Original line number Diff line number Diff line Loading @@ -410,6 +410,45 @@ escaping HTML. Similar to ``escape()``, except that it doesn't operate on pre-escaped strings, so it will not double escape. .. function:: format_html(format_string, *args, **kwargs) This is similar to `str.format`_, except that it is appropriate for building up HTML fragments. All args and kwargs are passed through :func:`conditional_escape` before being passed to ``str.format``. For the case of building up small HTML fragments, this function is to be preferred over string interpolation using ``%`` or ``str.format`` directly, because it applies escaping to all arguments - just like the Template system applies escaping by default. So, instead of writing: .. code-block:: python mark_safe(u"%s <b>%s</b> %s" % (some_html, escape(some_text), escape(some_other_text), )) you should instead use: .. code-block:: python format_html(u"%{0} <b>{1}</b> {2}", mark_safe(some_html), some_text, some_other_text) This has the advantage that you don't need to apply :func:`escape` to each argument and risk a bug and an XSS vulnerability if you forget one. Note that although this function uses ``str.format`` to do the interpolation, some of the formatting options provided by `str.format`_ (e.g. number formatting) will not work, since all arguments are passed through :func:`conditional_escape` which (ultimately) calls :func:`~django.utils.encoding.force_unicode` on the values. .. _str.format: http://docs.python.org/library/stdtypes.html#str.format ``django.utils.http`` ===================== Loading tests/regressiontests/utils/html.py +11 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,17 @@ class TestUtilsHtml(unittest.TestCase): # Verify it doesn't double replace &. self.check_output(f, '<&', '<&') def test_format_html(self): self.assertEqual( html.format_html(u"{0} {1} {third} {fourth}", u"< Dangerous >", html.mark_safe(u"<b>safe</b>"), third="< dangerous again", fourth=html.mark_safe(u"<i>safe again</i>") ), u"< Dangerous > <b>safe</b> < dangerous again <i>safe again</i>" ) def test_linebreaks(self): f = html.linebreaks items = ( Loading Loading
django/utils/html.py +31 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,37 @@ def conditional_escape(text): else: return escape(text) def format_html(format_string, *args, **kwargs): """ Similar to str.format, but passes all arguments through conditional_escape, and calls 'mark_safe' on the result. This function should be used instead of str.format or % interpolation to build up small HTML fragments. """ args_safe = map(conditional_escape, args) kwargs_safe = dict([(k, conditional_escape(v)) for (k, v) in kwargs.iteritems()]) return mark_safe(format_string.format(*args_safe, **kwargs_safe)) def format_html_join(sep, format_string, args_generator): """ A wrapper format_html, for the common case of a group of arguments that need to be formatted using the same format string, and then joined using 'sep'. 'sep' is also passed through conditional_escape. 'args_generator' should be an iterator that returns the sequence of 'args' that will be passed to format_html. Example: format_html_join('\n', "<li>{0} {1}</li>", ((u.first_name, u.last_name) for u in users)) """ return mark_safe(conditional_escape(sep).join( format_html(format_string, *tuple(args)) for args in args_generator)) def linebreaks(value, autoescape=False): """Converts newlines into <p> and <br />s.""" value = normalize_newlines(value) Loading
docs/ref/utils.txt +39 −0 Original line number Diff line number Diff line Loading @@ -410,6 +410,45 @@ escaping HTML. Similar to ``escape()``, except that it doesn't operate on pre-escaped strings, so it will not double escape. .. function:: format_html(format_string, *args, **kwargs) This is similar to `str.format`_, except that it is appropriate for building up HTML fragments. All args and kwargs are passed through :func:`conditional_escape` before being passed to ``str.format``. For the case of building up small HTML fragments, this function is to be preferred over string interpolation using ``%`` or ``str.format`` directly, because it applies escaping to all arguments - just like the Template system applies escaping by default. So, instead of writing: .. code-block:: python mark_safe(u"%s <b>%s</b> %s" % (some_html, escape(some_text), escape(some_other_text), )) you should instead use: .. code-block:: python format_html(u"%{0} <b>{1}</b> {2}", mark_safe(some_html), some_text, some_other_text) This has the advantage that you don't need to apply :func:`escape` to each argument and risk a bug and an XSS vulnerability if you forget one. Note that although this function uses ``str.format`` to do the interpolation, some of the formatting options provided by `str.format`_ (e.g. number formatting) will not work, since all arguments are passed through :func:`conditional_escape` which (ultimately) calls :func:`~django.utils.encoding.force_unicode` on the values. .. _str.format: http://docs.python.org/library/stdtypes.html#str.format ``django.utils.http`` ===================== Loading
tests/regressiontests/utils/html.py +11 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,17 @@ class TestUtilsHtml(unittest.TestCase): # Verify it doesn't double replace &. self.check_output(f, '<&', '<&') def test_format_html(self): self.assertEqual( html.format_html(u"{0} {1} {third} {fourth}", u"< Dangerous >", html.mark_safe(u"<b>safe</b>"), third="< dangerous again", fourth=html.mark_safe(u"<i>safe again</i>") ), u"< Dangerous > <b>safe</b> < dangerous again <i>safe again</i>" ) def test_linebreaks(self): f = html.linebreaks items = ( Loading