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"}),