Fix JSONField readonly admin display to use valid JSON

Previously, readonly JSONField values in the admin were shown as Python dicts, not valid JSON. Now, display_for_field uses json.dumps with the field's encoder to ensure correct JSON output.
Fixes # (if applicable)
This commit is contained in:
utkarsh.arya@zomato.com 2025-11-15 23:01:27 +00:00
parent 2e0f04507b
commit e09564d902
2 changed files with 56 additions and 0 deletions

View file

@ -1,5 +1,6 @@
import datetime
import decimal
import json
from collections import defaultdict
from django.core.exceptions import FieldDoesNotExist
@ -398,6 +399,8 @@ def display_for_field(value, field, empty_value_display):
return formats.number_format(value)
elif isinstance(field, models.FileField) and value:
return format_html('<a href="{}">{}</a>', value.url, value)
elif isinstance(field, models.JSONField):
return json.dumps(value, ensure_ascii=False, cls=field.encoder)
else:
return display_for_value(value, empty_value_display)

View file

@ -197,6 +197,59 @@ class UtilsTests(SimpleTestCase):
display_value = display_for_field(12345, models.IntegerField(), self.empty_value)
self.assertEqual(display_value, '12,345')
def test_json_display_for_field(self):
"""
JSONField values are displayed as valid JSON.
"""
tests = [
({'foo': 'bar'}, '{"foo": "bar"}'),
(['foo', 'bar'], '["foo", "bar"]'),
('foo', '"foo"'),
({'a': [1, 2]}, '{"a": [1, 2]}'),
(None, self.empty_value),
(True, 'true'),
(False, 'false'),
(123, '123'),
(45.67, '45.67'),
]
for value, expected_display in tests:
with self.subTest(value=value):
display_value = display_for_field(value, models.JSONField(), self.empty_value)
self.assertEqual(display_value, expected_display)
def test_json_display_for_field_custom_encoder(self):
"""
JSONField values are displayed as valid JSON with custom encoder.
"""
import json
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Decimal):
return str(obj)
return super().default(obj)
field = models.JSONField(encoder=CustomEncoder)
value = {'price': Decimal('10.50')}
display_value = display_for_field(value, field, self.empty_value)
# The custom encoder should convert Decimal to string
self.assertEqual(display_value, '{"price": "10.50"}')
def test_json_display_for_field_unicode(self):
"""
JSONField values with Unicode characters are properly displayed.
"""
tests = [
({'name': 'José'}, '{"name": "José"}'),
({'emoji': '😀'}, '{"emoji": "😀"}'),
({'chinese': '你好'}, '{"chinese": "你好"}'),
({'mixed': 'Hello 世界 🌍'}, '{"mixed": "Hello 世界 🌍"}'),
]
for value, expected_display in tests:
with self.subTest(value=value):
display_value = display_for_field(value, models.JSONField(), self.empty_value)
self.assertEqual(display_value, expected_display)
def test_list_display_for_value(self):
display_value = display_for_value([1, 2, 3], self.empty_value)
self.assertEqual(display_value, '1, 2, 3')