Browse Source

Fixed #33779 -- Allowed customizing encoder class in django.utils.html.json_script().

Hrushikesh Vaidya 2 years ago
parent
commit
72e41a0df6
4 changed files with 27 additions and 4 deletions
  1. 4 2
      django/utils/html.py
  2. 10 1
      docs/ref/utils.txt
  3. 2 1
      docs/releases/4.2.txt
  4. 11 0
      tests/utils_tests/test_html.py

+ 4 - 2
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 = '<script id="{}" type="application/json">{}</script>'
         args = (element_id, mark_safe(json_str))

+ 10 - 1
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")
         '<script id="hello-data" type="application/json">{"hello": "world"}</script>'
 
+    The ``encoder``, which defaults to
+    :class:`django.core.serializers.json.DjangoJSONEncoder`, will be used to
+    serialize the data. See :ref:`JSON serialization
+    <serialization-formats-json>` 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

+ 2 - 1
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
 ~~~~~~~~~~

+ 11 - 0
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),
+            '<script type="application/json">{"hello": "world"}</script>',
+        )
+
     def test_json_script_without_id(self):
         self.assertHTMLEqual(
             json_script({"key": "value"}),