Fixed #26215 -- Fixed RangeField/ArrayField serialization with None values

Also added tests for HStoreField and JSONField.
Thanks Aleksey Bukin for the report and Tim Graham for the initial patch and
the review.
This commit is contained in:
Claude Paroz 2016-02-15 19:28:49 +01:00
parent b09b71bf34
commit 928c12eb1a
8 changed files with 44 additions and 11 deletions

View File

@ -106,6 +106,9 @@ class ArrayField(Field):
base_field = self.base_field
for val in vals:
if val is None:
values.append(None)
else:
obj = AttributeSetter(base_field.attname, val)
values.append(base_field.value_to_string(obj))
return json.dumps(values)

View File

@ -51,7 +51,11 @@ class RangeField(models.Field):
base_field = self.base_field
result = {"bounds": value._bounds}
for end in ('lower', 'upper'):
obj = AttributeSetter(base_field.attname, getattr(value, end))
val = getattr(value, end)
if val is None:
result[end] = None
else:
obj = AttributeSetter(base_field.attname, val)
result[end] = base_field.value_to_string(obj)
return json.dumps(result)

View File

@ -17,3 +17,7 @@ Bugfixes
* Made ``forms.FileField`` and ``utils.translation.lazy_number()`` picklable
(:ticket:`26212`).
* Fixed :class:`~django.contrib.postgres.fields.RangeField` and
:class:`~django.contrib.postgres.fields.ArrayField` serialization with
``None`` values (:ticket:`26215`).

View File

@ -27,3 +27,7 @@ Bugfixes
* Made ``forms.FileField`` and ``utils.translation.lazy_number()`` picklable
(:ticket:`26212`).
* Fixed :class:`~django.contrib.postgres.fields.RangeField` and
:class:`~django.contrib.postgres.fields.ArrayField` serialization with
``None`` values (:ticket:`26215`).

View File

@ -448,17 +448,17 @@ class TestMigrations(TransactionTestCase):
class TestSerialization(PostgreSQLTestCase):
test_data = (
'[{"fields": {"field": "[\\"1\\", \\"2\\"]"}, "model": "postgres_tests.integerarraymodel", "pk": null}]'
'[{"fields": {"field": "[\\"1\\", \\"2\\", null]"}, "model": "postgres_tests.integerarraymodel", "pk": null}]'
)
def test_dumping(self):
instance = IntegerArrayModel(field=[1, 2])
instance = IntegerArrayModel(field=[1, 2, None])
data = serializers.serialize('json', [instance])
self.assertEqual(json.loads(data), json.loads(self.test_data))
def test_loading(self):
instance = list(serializers.deserialize('json', self.test_data))[0].object
self.assertEqual(instance.field, [1, 2])
self.assertEqual(instance.field, [1, 2, None])
class TestValidation(PostgreSQLTestCase):

View File

@ -165,7 +165,8 @@ class TestQuerying(PostgreSQLTestCase):
class TestSerialization(PostgreSQLTestCase):
test_data = '[{"fields": {"field": "{\\"a\\": \\"b\\"}"}, "model": "postgres_tests.hstoremodel", "pk": null}]'
test_data = ('[{"fields": {"field": "{\\"a\\": \\"b\\"}"}, '
'"model": "postgres_tests.hstoremodel", "pk": null}]')
def test_dumping(self):
instance = HStoreModel(field={'a': 'b'})
@ -176,6 +177,12 @@ class TestSerialization(PostgreSQLTestCase):
instance = list(serializers.deserialize('json', self.test_data))[0].object
self.assertEqual(instance.field, {'a': 'b'})
def test_roundtrip_with_null(self):
instance = HStoreModel(field={'a': 'b', 'c': None})
data = serializers.serialize('json', [instance])
new_instance = list(serializers.deserialize('json', data))[0].object
self.assertEqual(instance.field, new_instance.field)
class TestValidation(PostgreSQLTestCase):

View File

@ -213,16 +213,16 @@ class TestQuerying(TestCase):
@skipUnlessPG94
class TestSerialization(TestCase):
test_data = '[{"fields": {"field": {"a": "b"}}, "model": "postgres_tests.jsonmodel", "pk": null}]'
test_data = '[{"fields": {"field": {"a": "b", "c": null}}, "model": "postgres_tests.jsonmodel", "pk": null}]'
def test_dumping(self):
instance = JSONModel(field={'a': 'b'})
instance = JSONModel(field={'a': 'b', 'c': None})
data = serializers.serialize('json', [instance])
self.assertJSONEqual(data, self.test_data)
def test_loading(self):
instance = list(serializers.deserialize('json', self.test_data))[0].object
self.assertEqual(instance.field, {'a': 'b'})
self.assertEqual(instance.field, {'a': 'b', 'c': None})
class TestValidation(PostgreSQLTestCase):

View File

@ -309,6 +309,17 @@ class TestSerialization(PostgreSQLTestCase):
self.assertEqual(instance.dates, DateRange(self.lower_date, self.upper_date))
self.assertEqual(instance.timestamps, DateTimeTZRange(self.lower_dt, self.upper_dt))
def test_serialize_range_with_null(self):
instance = RangesModel(ints=NumericRange(None, 10))
data = serializers.serialize('json', [instance])
new_instance = list(serializers.deserialize('json', data))[0].object
self.assertEqual(new_instance.ints, NumericRange(None, 10))
instance = RangesModel(ints=NumericRange(10, None))
data = serializers.serialize('json', [instance])
new_instance = list(serializers.deserialize('json', data))[0].object
self.assertEqual(new_instance.ints, NumericRange(10, None))
class TestValidators(PostgreSQLTestCase):