mirror of
https://github.com/django/django.git
synced 2025-11-19 19:24:46 +00:00
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:
parent
2e0f04507b
commit
e09564d902
2 changed files with 56 additions and 0 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import datetime
|
import datetime
|
||||||
import decimal
|
import decimal
|
||||||
|
import json
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
|
|
@ -398,6 +399,8 @@ def display_for_field(value, field, empty_value_display):
|
||||||
return formats.number_format(value)
|
return formats.number_format(value)
|
||||||
elif isinstance(field, models.FileField) and value:
|
elif isinstance(field, models.FileField) and value:
|
||||||
return format_html('<a href="{}">{}</a>', value.url, 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:
|
else:
|
||||||
return display_for_value(value, empty_value_display)
|
return display_for_value(value, empty_value_display)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,59 @@ class UtilsTests(SimpleTestCase):
|
||||||
display_value = display_for_field(12345, models.IntegerField(), self.empty_value)
|
display_value = display_for_field(12345, models.IntegerField(), self.empty_value)
|
||||||
self.assertEqual(display_value, '12,345')
|
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):
|
def test_list_display_for_value(self):
|
||||||
display_value = display_for_value([1, 2, 3], self.empty_value)
|
display_value = display_for_value([1, 2, 3], self.empty_value)
|
||||||
self.assertEqual(display_value, '1, 2, 3')
|
self.assertEqual(display_value, '1, 2, 3')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue