From 47651eadb8ca7aacddad41da4df64fd2af11faae Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Mon, 23 Mar 2020 19:31:49 +0100 Subject: [PATCH] Fixed #30583 -- Fixed handling JSONFields in XML serializer. Co-authored-by: Chason Chaffin --- django/core/serializers/xml_serializer.py | 12 ++++++++++-- tests/model_fields/test_jsonfield.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py index 07de9428e7f..88bfa590321 100644 --- a/django/core/serializers/xml_serializer.py +++ b/django/core/serializers/xml_serializer.py @@ -1,7 +1,7 @@ """ XML serializer. """ - +import json from xml.dom import pulldom from xml.sax import handler from xml.sax.expatreader import ExpatParser as _ExpatParser @@ -75,8 +75,13 @@ class Serializer(base.Serializer): # Get a "string version" of the object's data. if getattr(obj, field.name) is not None: + value = field.value_to_string(obj) + if field.get_internal_type() == 'JSONField': + # Dump value since JSONField.value_to_string() doesn't output + # strings. + value = json.dumps(value, cls=field.encoder) try: - self.xml.characters(field.value_to_string(obj)) + self.xml.characters(value) except UnserializableContentError: raise ValueError("%s.%s (pk:%s) contains unserializable characters" % ( obj.__class__.__name__, field.name, obj.pk)) @@ -232,6 +237,9 @@ class Deserializer(base.Deserializer): value = None else: value = field.to_python(getInnerText(field_node).strip()) + # Load value since JSONField.to_python() outputs strings. + if field.get_internal_type() == 'JSONField': + value = json.loads(value, cls=field.decoder) data[field.name] = value obj = base.build_instance(Model, data, self.db) diff --git a/tests/model_fields/test_jsonfield.py b/tests/model_fields/test_jsonfield.py index 1e92b34791c..bc0a89fd7df 100644 --- a/tests/model_fields/test_jsonfield.py +++ b/tests/model_fields/test_jsonfield.py @@ -149,6 +149,21 @@ class TestSerialization(SimpleTestCase): )[0].object self.assertEqual(instance.value, value) + def test_xml_serialization(self): + test_xml_data = ( + '' + '' + '%s' + '' + ) + for value, serialized in self.test_values: + with self.subTest(value=value): + instance = NullableJSONModel(value=value) + data = serializers.serialize('xml', [instance], fields=['value']) + self.assertXMLEqual(data, test_xml_data % serialized) + new_instance = list(serializers.deserialize('xml', data))[0].object + self.assertEqual(new_instance.value, instance.value) + @skipUnlessDBFeature('supports_json_field') class TestSaveLoad(TestCase):