summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2016-02-15 19:28:49 +0100
committerClaude Paroz <claude@2xlibre.net>2016-02-16 21:07:05 +0100
commit928c12eb1a75dbcab22b64f8cf0afb17389c20d2 (patch)
treeb8f20f14e121e816772056d639a6a14f60adffe8
parentb09b71bf3468c67a9c08654e7aa8b99efe59ebee (diff)
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.
-rw-r--r--django/contrib/postgres/fields/array.py7
-rw-r--r--django/contrib/postgres/fields/ranges.py8
-rw-r--r--docs/releases/1.8.10.txt4
-rw-r--r--docs/releases/1.9.3.txt4
-rw-r--r--tests/postgres_tests/test_array.py6
-rw-r--r--tests/postgres_tests/test_hstore.py9
-rw-r--r--tests/postgres_tests/test_json.py6
-rw-r--r--tests/postgres_tests/test_ranges.py11
8 files changed, 44 insertions, 11 deletions
diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py
index 736849eb6a..f8009bfb8a 100644
--- a/django/contrib/postgres/fields/array.py
+++ b/django/contrib/postgres/fields/array.py
@@ -106,8 +106,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):
diff --git a/django/contrib/postgres/fields/ranges.py b/django/contrib/postgres/fields/ranges.py
index bf3f8cb9a4..5bce0743f0 100644
--- a/django/contrib/postgres/fields/ranges.py
+++ b/django/contrib/postgres/fields/ranges.py
@@ -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):
diff --git a/docs/releases/1.8.10.txt b/docs/releases/1.8.10.txt
index 4eea5a3b7b..b29000eb20 100644
--- a/docs/releases/1.8.10.txt
+++ b/docs/releases/1.8.10.txt
@@ -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`).
diff --git a/docs/releases/1.9.3.txt b/docs/releases/1.9.3.txt
index 05c6542329..af7bcf21bb 100644
--- a/docs/releases/1.9.3.txt
+++ b/docs/releases/1.9.3.txt
@@ -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`).
diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py
index 24a47db1d7..5df25c1c0f 100644
--- a/tests/postgres_tests/test_array.py
+++ b/tests/postgres_tests/test_array.py
@@ -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):
diff --git a/tests/postgres_tests/test_hstore.py b/tests/postgres_tests/test_hstore.py
index 13c08386e2..8ebd757098 100644
--- a/tests/postgres_tests/test_hstore.py
+++ b/tests/postgres_tests/test_hstore.py
@@ -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):
diff --git a/tests/postgres_tests/test_json.py b/tests/postgres_tests/test_json.py
index b4f0dd4ecf..59e5fe3fe7 100644
--- a/tests/postgres_tests/test_json.py
+++ b/tests/postgres_tests/test_json.py
@@ -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):
diff --git a/tests/postgres_tests/test_ranges.py b/tests/postgres_tests/test_ranges.py
index dd676f96be..692fb54a89 100644
--- a/tests/postgres_tests/test_ranges.py
+++ b/tests/postgres_tests/test_ranges.py
@@ -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):