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

This commit is contained in:
Hrushikesh Vaidya 2022-06-23 14:20:20 +05:30 committed by Mariusz Felisiak
parent 0ee03a439b
commit 72e41a0df6
4 changed files with 27 additions and 4 deletions

View File

@ -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 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 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 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: if element_id:
template = '<script id="{}" type="application/json">{}</script>' template = '<script id="{}" type="application/json">{}</script>'
args = (element_id, mark_safe(json_str)) args = (element_id, mark_safe(json_str))

View File

@ -655,7 +655,7 @@ escaping HTML.
((u.first_name, u.last_name) for u in users) ((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 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 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") >> json_script({"hello": "world"}, element_id="hello-data")
'<script id="hello-data" type="application/json">{"hello": "world"}</script>' '<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 .. versionchanged:: 4.1
In older versions, the ``element_id`` argument was required. In older versions, the ``element_id`` argument was required.
.. versionchanged:: 4.2
The ``encoder`` argument was added.
.. function:: strip_tags(value) .. function:: strip_tags(value)
Tries to remove anything that looks like an HTML tag from the string, that Tries to remove anything that looks like an HTML tag from the string, that

View File

@ -214,7 +214,8 @@ URLs
Utilities Utilities
~~~~~~~~~ ~~~~~~~~~
* ... * The new ``encoder`` parameter for :meth:`django.utils.html.json_script`
function allows customizing a JSON encoder class.
Validators Validators
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -1,6 +1,7 @@
import os import os
from datetime import datetime from datetime import datetime
from django.core.serializers.json import DjangoJSONEncoder
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.utils.functional import lazystr from django.utils.functional import lazystr
from django.utils.html import ( from django.utils.html import (
@ -211,6 +212,16 @@ class TestUtilsHtml(SimpleTestCase):
with self.subTest(arg=arg): with self.subTest(arg=arg):
self.assertEqual(json_script(arg, "test_id"), expected) 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): def test_json_script_without_id(self):
self.assertHTMLEqual( self.assertHTMLEqual(
json_script({"key": "value"}), json_script({"key": "value"}),