[1.8.x] Fixed #26215 -- Fixed RangeField/ArrayField serialization with None values

Also added tests for HStoreField.
Thanks Aleksey Bukin for the report and Tim Graham for the initial patch and
the review.
Backport of 928c12eb1 from master.
This commit is contained in:
Claude Paroz 2016-02-15 19:28:49 +01:00
parent 766fbcb1d3
commit 5bce665974
6 changed files with 39 additions and 8 deletions

View File

@ -95,8 +95,11 @@ class ArrayField(Field):
base_field = self.base_field
for val in vals:
obj = AttributeSetter(base_field.attname, val)
values.append(base_field.value_to_string(obj))
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)
def get_transform(self, name):

View File

@ -51,8 +51,12 @@ 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))
result[end] = base_field.value_to_string(obj)
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)
def formfield(self, **kwargs):

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

@ -412,16 +412,18 @@ class TestMigrations(TransactionTestCase):
class TestSerialization(TestCase):
test_data = '[{"fields": {"field": "[\\"1\\", \\"2\\"]"}, "model": "postgres_tests.integerarraymodel", "pk": null}]'
test_data = (
'[{"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(TestCase):

View File

@ -130,7 +130,8 @@ class TestQuerying(TestCase):
class TestSerialization(TestCase):
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'})
@ -141,6 +142,12 @@ class TestSerialization(TestCase):
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(TestCase):

View File

@ -225,6 +225,17 @@ class TestSerialization(TestCase):
self.assertEqual(instance.floats, NumericRange(empty=True))
self.assertEqual(instance.bigints, None)
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(TestCase):