summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Tamlyn <marc.tamlyn@gmail.com>2015-06-06 13:41:00 +0100
committerMarc Tamlyn <marc.tamlyn@gmail.com>2015-06-06 13:41:00 +0100
commitd58816bd6bf93a878085d35d3ed4609efeb0acfa (patch)
treea5a42e635e677bed9645f0590f75cd72fa57f8f9
parent3fd754f12df42d173b6e9a93e7c32f8f5be55e7f (diff)
parent8a842148b6deaab021526e2689279cf5e232945f (diff)
Merge pull request #4818 from dracos/24937-ranging-to-victory
Fixed #24937 -- fix serialization of Date(Time)RangeField.
-rw-r--r--django/contrib/postgres/fields/array.py7
-rw-r--r--django/contrib/postgres/fields/ranges.py24
-rw-r--r--django/contrib/postgres/fields/utils.py3
-rw-r--r--docs/releases/1.9.txt4
-rw-r--r--tests/postgres_tests/test_ranges.py23
5 files changed, 44 insertions, 17 deletions
diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py
index 9da7ec4cb7..f9242f086b 100644
--- a/django/contrib/postgres/fields/array.py
+++ b/django/contrib/postgres/fields/array.py
@@ -8,12 +8,9 @@ from django.db.models import Field, IntegerField, Transform
from django.utils import six
from django.utils.translation import string_concat, ugettext_lazy as _
-__all__ = ['ArrayField']
-
+from .utils import AttributeSetter
-class AttributeSetter(object):
- def __init__(self, name, value):
- setattr(self, name, value)
+__all__ = ['ArrayField']
class ArrayField(Field):
diff --git a/django/contrib/postgres/fields/ranges.py b/django/contrib/postgres/fields/ranges.py
index 6e0f8e2284..13ba606c79 100644
--- a/django/contrib/postgres/fields/ranges.py
+++ b/django/contrib/postgres/fields/ranges.py
@@ -6,6 +6,8 @@ from django.contrib.postgres import forms, lookups
from django.db import models
from django.utils import six
+from .utils import AttributeSetter
+
__all__ = [
'RangeField', 'IntegerRangeField', 'BigIntegerRangeField',
'FloatRangeField', 'DateTimeRangeField', 'DateRangeField',
@@ -26,22 +28,32 @@ class RangeField(models.Field):
def to_python(self, value):
if isinstance(value, six.string_types):
- value = self.range_type(**json.loads(value))
+ # Assume we're deserializing
+ vals = json.loads(value)
+ for end in ('lower', 'upper'):
+ if end in vals:
+ vals[end] = self.base_field.to_python(vals[end])
+ value = self.range_type(**vals)
elif isinstance(value, (list, tuple)):
value = self.range_type(value[0], value[1])
return value
+ def set_attributes_from_name(self, name):
+ super(RangeField, self).set_attributes_from_name(name)
+ self.base_field.set_attributes_from_name(name)
+
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
if value is None:
return None
if value.isempty:
return json.dumps({"empty": True})
- return json.dumps({
- "lower": value.lower,
- "upper": value.upper,
- "bounds": value._bounds,
- })
+ 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)
+ return json.dumps(result)
def formfield(self, **kwargs):
kwargs.setdefault('form_class', self.form_field)
diff --git a/django/contrib/postgres/fields/utils.py b/django/contrib/postgres/fields/utils.py
new file mode 100644
index 0000000000..424a78f521
--- /dev/null
+++ b/django/contrib/postgres/fields/utils.py
@@ -0,0 +1,3 @@
+class AttributeSetter(object):
+ def __init__(self, name, value):
+ setattr(self, name, value)
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index 793dcd6a82..c6467d9f65 100644
--- a/docs/releases/1.9.txt
+++ b/docs/releases/1.9.txt
@@ -102,6 +102,10 @@ Minor features
* Added :class:`~django.contrib.postgres.fields.JSONField`.
* Added :doc:`/ref/contrib/postgres/aggregates`.
+* Fixed serialization of
+ :class:`~django.contrib.postgres.fields.DateRangeField` and
+ :class:`~django.contrib.postgres.fields.DateTimeRangeField`.
+
:mod:`django.contrib.redirects`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/postgres_tests/test_ranges.py b/tests/postgres_tests/test_ranges.py
index 2461130b35..7d7fb33c4d 100644
--- a/tests/postgres_tests/test_ranges.py
+++ b/tests/postgres_tests/test_ranges.py
@@ -291,26 +291,37 @@ class TestQueringWithRanges(TestCase):
@skipUnlessPG92
class TestSerialization(TestCase):
test_data = (
- '[{"fields": {"ints": "{\\"upper\\": 10, \\"lower\\": 0, '
+ '[{"fields": {"ints": "{\\"upper\\": \\"10\\", \\"lower\\": \\"0\\", '
'\\"bounds\\": \\"[)\\"}", "floats": "{\\"empty\\": true}", '
- '"bigints": null, "timestamps": null, "dates": null}, '
+ '"bigints": null, "timestamps": "{\\"upper\\": \\"2014-02-02T12:12:12+00:00\\", '
+ '\\"lower\\": \\"2014-01-01T00:00:00+00:00\\", \\"bounds\\": \\"[)\\"}", '
+ '"dates": "{\\"upper\\": \\"2014-02-02\\", \\"lower\\": \\"2014-01-01\\", \\"bounds\\": \\"[)\\"}" }, '
'"model": "postgres_tests.rangesmodel", "pk": null}]'
)
+ lower_date = datetime.date(2014, 1, 1)
+ upper_date = datetime.date(2014, 2, 2)
+ lower_dt = datetime.datetime(2014, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
+ upper_dt = datetime.datetime(2014, 2, 2, 12, 12, 12, tzinfo=timezone.utc)
+
def test_dumping(self):
- instance = RangesModel(ints=NumericRange(0, 10), floats=NumericRange(empty=True))
+ instance = RangesModel(ints=NumericRange(0, 10), floats=NumericRange(empty=True),
+ timestamps=DateTimeTZRange(self.lower_dt, self.upper_dt),
+ dates=DateRange(self.lower_date, self.upper_date))
data = serializers.serialize('json', [instance])
dumped = json.loads(data)
- dumped[0]['fields']['ints'] = json.loads(dumped[0]['fields']['ints'])
+ for field in ('ints', 'dates', 'timestamps'):
+ dumped[0]['fields'][field] = json.loads(dumped[0]['fields'][field])
check = json.loads(self.test_data)
- check[0]['fields']['ints'] = json.loads(check[0]['fields']['ints'])
+ for field in ('ints', 'dates', 'timestamps'):
+ check[0]['fields'][field] = json.loads(check[0]['fields'][field])
self.assertEqual(dumped, check)
def test_loading(self):
instance = list(serializers.deserialize('json', self.test_data))[0].object
self.assertEqual(instance.ints, NumericRange(0, 10))
self.assertEqual(instance.floats, NumericRange(empty=True))
- self.assertEqual(instance.dates, None)
+ self.assertEqual(instance.bigints, None)
class TestValidators(PostgreSQLTestCase):