diff --git a/django/utils/html.py b/django/utils/html.py index d0bc97be80..007602a14a 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -59,7 +59,7 @@ _json_script_escapes = { } -def json_script(value, element_id=None): +def json_script(value, element_id=None, encoder=None): """ Escape all the HTML/XML special characters with their unicode escapes, so value is safe to be output anywhere except for inside a tag attribute. Wrap @@ -67,7 +67,9 @@ def json_script(value, element_id=None): """ from django.core.serializers.json import DjangoJSONEncoder - json_str = json.dumps(value, cls=DjangoJSONEncoder).translate(_json_script_escapes) + json_str = json.dumps(value, cls=encoder or DjangoJSONEncoder).translate( + _json_script_escapes + ) if element_id: template = '' args = (element_id, mark_safe(json_str)) diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt index 6b44e81611..d296d2bda1 100644 --- a/docs/ref/utils.txt +++ b/docs/ref/utils.txt @@ -655,7 +655,7 @@ escaping HTML. ((u.first_name, u.last_name) for u in users) ) -.. function:: json_script(value, element_id=None) +.. function:: json_script(value, element_id=None, encoder=None) Escapes all HTML/XML special characters with their Unicode escapes, so value is safe for use with JavaScript. Also wraps the escaped JSON in a @@ -665,10 +665,19 @@ escaping HTML. >> json_script({"hello": "world"}, element_id="hello-data") '' + The ``encoder``, which defaults to + :class:`django.core.serializers.json.DjangoJSONEncoder`, will be used to + serialize the data. See :ref:`JSON serialization + ` for more details about this serializer. + .. versionchanged:: 4.1 In older versions, the ``element_id`` argument was required. + .. versionchanged:: 4.2 + + The ``encoder`` argument was added. + .. function:: strip_tags(value) Tries to remove anything that looks like an HTML tag from the string, that diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt index ca1c2a0eaa..649fb797c6 100644 --- a/docs/releases/4.2.txt +++ b/docs/releases/4.2.txt @@ -214,7 +214,8 @@ URLs Utilities ~~~~~~~~~ -* ... +* The new ``encoder`` parameter for :meth:`django.utils.html.json_script` + function allows customizing a JSON encoder class. Validators ~~~~~~~~~~ diff --git a/tests/utils_tests/test_html.py b/tests/utils_tests/test_html.py index 22a43fd4cd..b7a7396075 100644 --- a/tests/utils_tests/test_html.py +++ b/tests/utils_tests/test_html.py @@ -1,6 +1,7 @@ import os from datetime import datetime +from django.core.serializers.json import DjangoJSONEncoder from django.test import SimpleTestCase from django.utils.functional import lazystr from django.utils.html import ( @@ -211,6 +212,16 @@ class TestUtilsHtml(SimpleTestCase): with self.subTest(arg=arg): self.assertEqual(json_script(arg, "test_id"), expected) + def test_json_script_custom_encoder(self): + class CustomDjangoJSONEncoder(DjangoJSONEncoder): + def encode(self, o): + return '{"hello": "world"}' + + self.assertHTMLEqual( + json_script({}, encoder=CustomDjangoJSONEncoder), + '', + ) + def test_json_script_without_id(self): self.assertHTMLEqual( json_script({"key": "value"}),