Commit 9c964cf3 by Stephan Groß

Add new ISO8601 setting + integration

parent a9d36d47
...@@ -4,3 +4,6 @@ VERSION = __version__ # synonym ...@@ -4,3 +4,6 @@ VERSION = __version__ # synonym
# Header encoding (see RFC5987) # Header encoding (see RFC5987)
HTTP_HEADER_ENCODING = 'iso-8859-1' HTTP_HEADER_ENCODING = 'iso-8859-1'
# Default input and output format
ISO8601 = 'iso-8601'
\ No newline at end of file
...@@ -11,9 +11,11 @@ from django.core.exceptions import ValidationError ...@@ -11,9 +11,11 @@ from django.core.exceptions import ValidationError
from django.conf import settings from django.conf import settings
from django import forms from django import forms
from django.forms import widgets from django.forms import widgets
from django.utils.dateparse import parse_date, parse_datetime, parse_time
from django.utils.encoding import is_protected_type from django.utils.encoding import is_protected_type
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import ISO8601
from rest_framework.compat import timezone from rest_framework.compat import timezone
from rest_framework.compat import BytesIO from rest_framework.compat import BytesIO
from rest_framework.compat import six from rest_framework.compat import six
...@@ -472,6 +474,15 @@ class DateField(WritableField): ...@@ -472,6 +474,15 @@ class DateField(WritableField):
return value return value
for format in self.input_formats: for format in self.input_formats:
if format.lower() == ISO8601:
try:
parsed = parse_date(value)
except (ValueError, TypeError):
pass
else:
if parsed is not None:
return parsed
else:
try: try:
parsed = datetime.datetime.strptime(value, format) parsed = datetime.datetime.strptime(value, format)
except (ValueError, TypeError): except (ValueError, TypeError):
...@@ -479,14 +490,14 @@ class DateField(WritableField): ...@@ -479,14 +490,14 @@ class DateField(WritableField):
else: else:
return parsed.date() return parsed.date()
date_input_formats = '; '.join(self.input_formats) date_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'YYYY-MM-DD')
msg = self.error_messages['invalid'] % get_readable_date_format(date_input_formats) msg = self.error_messages['invalid'] % get_readable_date_format(date_input_formats)
raise ValidationError(msg) raise ValidationError(msg)
def to_native(self, value): def to_native(self, value):
if self.output_format is not None: if self.output_format.lower() == ISO8601:
return value.strftime(self.output_format)
return value.isoformat() return value.isoformat()
return value.strftime(self.output_format)
class DateTimeField(WritableField): class DateTimeField(WritableField):
...@@ -525,6 +536,15 @@ class DateTimeField(WritableField): ...@@ -525,6 +536,15 @@ class DateTimeField(WritableField):
return value return value
for format in self.input_formats: for format in self.input_formats:
if format.lower() == ISO8601:
try:
parsed = parse_datetime(value)
except (ValueError, TypeError):
pass
else:
if parsed is not None:
return parsed
else:
try: try:
parsed = datetime.datetime.strptime(value, format) parsed = datetime.datetime.strptime(value, format)
except (ValueError, TypeError): except (ValueError, TypeError):
...@@ -532,14 +552,14 @@ class DateTimeField(WritableField): ...@@ -532,14 +552,14 @@ class DateTimeField(WritableField):
else: else:
return parsed return parsed
datetime_input_formats = '; '.join(self.input_formats) datetime_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]')
msg = self.error_messages['invalid'] % get_readable_date_format(datetime_input_formats) msg = self.error_messages['invalid'] % get_readable_date_format(datetime_input_formats)
raise ValidationError(msg) raise ValidationError(msg)
def to_native(self, value): def to_native(self, value):
if self.output_format is not None: if self.output_format.lower() == ISO8601:
return value.strftime(self.output_format)
return value.isoformat() return value.isoformat()
return value.strftime(self.output_format)
class TimeField(WritableField): class TimeField(WritableField):
...@@ -565,6 +585,15 @@ class TimeField(WritableField): ...@@ -565,6 +585,15 @@ class TimeField(WritableField):
return value return value
for format in self.input_formats: for format in self.input_formats:
if format.lower() == ISO8601:
try:
parsed = parse_time(value)
except (ValueError, TypeError):
pass
else:
if parsed is not None:
return parsed
else:
try: try:
parsed = datetime.datetime.strptime(value, format) parsed = datetime.datetime.strptime(value, format)
except (ValueError, TypeError): except (ValueError, TypeError):
...@@ -572,14 +601,14 @@ class TimeField(WritableField): ...@@ -572,14 +601,14 @@ class TimeField(WritableField):
else: else:
return parsed.time() return parsed.time()
time_input_formats = '; '.join(self.input_formats) time_input_formats = '; '.join(self.input_formats).replace(ISO8601, 'HH:MM[:ss[.uuuuuu]]')
msg = self.error_messages['invalid'] % get_readable_date_format(time_input_formats) msg = self.error_messages['invalid'] % get_readable_date_format(time_input_formats)
raise ValidationError(msg) raise ValidationError(msg)
def to_native(self, value): def to_native(self, value):
if self.output_format is not None: if self.output_format.lower() == ISO8601:
return value.strftime(self.output_format)
return value.isoformat() return value.isoformat()
return value.strftime(self.output_format)
class IntegerField(WritableField): class IntegerField(WritableField):
......
...@@ -18,8 +18,11 @@ REST framework settings, checking for user settings first, then falling ...@@ -18,8 +18,11 @@ REST framework settings, checking for user settings first, then falling
back to the defaults. back to the defaults.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
from django.utils import importlib from django.utils import importlib
from rest_framework import ISO8601
from rest_framework.compat import six from rest_framework.compat import six
...@@ -79,24 +82,19 @@ DEFAULTS = { ...@@ -79,24 +82,19 @@ DEFAULTS = {
# Input and output formats # Input and output formats
'DATE_INPUT_FORMATS': ( 'DATE_INPUT_FORMATS': (
'%Y-%m-%d', # '1984-07-31' ISO8601,
), ),
'DATE_OUTPUT_FORMAT': None, 'DATE_OUTPUT_FORMAT': ISO8601,
'DATETIME_INPUT_FORMATS': ( 'DATETIME_INPUT_FORMATS': (
'%Y-%m-%d', # '1984-07-31' ISO8601,
'%Y-%m-%d %H:%M', # '1984-07-31 04:31'
'%Y-%m-%d %H:%M:%S', # '1984-07-31 04:31:59'
'%Y-%m-%d %H:%M:%S.%f', # '1984-07-31 04:31:59.000200'
), ),
'DATETIME_OUTPUT_FORMAT': None, 'DATETIME_OUTPUT_FORMAT': ISO8601,
'TIME_INPUT_FORMATS': ( 'TIME_INPUT_FORMATS': (
'%H:%M', # '04:31' ISO8601,
'%H:%M:%S', # '04:31:59'
'%H:%M:%S.%f', # '04:31:59.000200'
), ),
'TIME_OUTPUT_FORMAT': None, 'TIME_OUTPUT_FORMAT': ISO8601,
} }
......
...@@ -173,30 +173,26 @@ class DateTimeFieldTest(TestCase): ...@@ -173,30 +173,26 @@ class DateTimeFieldTest(TestCase):
Make sure from_native() accepts default iso input formats. Make sure from_native() accepts default iso input formats.
""" """
f = serializers.DateTimeField() f = serializers.DateTimeField()
result_1 = f.from_native('1984-07-31') result_1 = f.from_native('1984-07-31 04:31')
result_2 = f.from_native('1984-07-31 04:31') result_2 = f.from_native('1984-07-31 04:31:59')
result_3 = f.from_native('1984-07-31 04:31:59') result_3 = f.from_native('1984-07-31 04:31:59.000200')
result_4 = f.from_native('1984-07-31 04:31:59.000200')
self.assertEqual(datetime.datetime(1984, 7, 31), result_1) self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_1)
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_2) self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_2)
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_3) self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_3)
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_4)
def test_from_native_datetime_datetime(self): def test_from_native_datetime_datetime(self):
""" """
Make sure from_native() accepts a datetime.datetime instance. Make sure from_native() accepts a datetime.datetime instance.
""" """
f = serializers.DateTimeField() f = serializers.DateTimeField()
result_1 = f.from_native(datetime.datetime(1984, 7, 31)) result_1 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31))
result_2 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31)) result_2 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
result_3 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59)) result_3 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
result_4 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
self.assertEqual(result_1, datetime.datetime(1984, 7, 31)) self.assertEqual(result_1, datetime.datetime(1984, 7, 31, 4, 31))
self.assertEqual(result_2, datetime.datetime(1984, 7, 31, 4, 31)) self.assertEqual(result_2, datetime.datetime(1984, 7, 31, 4, 31, 59))
self.assertEqual(result_3, datetime.datetime(1984, 7, 31, 4, 31, 59)) self.assertEqual(result_3, datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
self.assertEqual(result_4, datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
def test_from_native_custom_format(self): def test_from_native_custom_format(self):
""" """
...@@ -239,8 +235,7 @@ class DateTimeFieldTest(TestCase): ...@@ -239,8 +235,7 @@ class DateTimeFieldTest(TestCase):
f.from_native('04:61:59') f.from_native('04:61:59')
except validators.ValidationError as e: except validators.ValidationError as e:
self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: "
"YYYY-MM-DD; YYYY-MM-DD HH:MM; YYYY-MM-DD HH:MM:SS; " "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"])
"YYYY-MM-DD HH:MM:SS.uuuuuu"])
else: else:
self.fail("ValidationError was not properly raised") self.fail("ValidationError was not properly raised")
...@@ -254,8 +249,7 @@ class DateTimeFieldTest(TestCase): ...@@ -254,8 +249,7 @@ class DateTimeFieldTest(TestCase):
f.from_native('04 -- 31') f.from_native('04 -- 31')
except validators.ValidationError as e: except validators.ValidationError as e:
self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: " self.assertEqual(e.messages, ["Datetime has wrong format. Use one of these formats instead: "
"YYYY-MM-DD; YYYY-MM-DD HH:MM; YYYY-MM-DD HH:MM:SS; " "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"])
"YYYY-MM-DD HH:MM:SS.uuuuuu"])
else: else:
self.fail("ValidationError was not properly raised") self.fail("ValidationError was not properly raised")
...@@ -364,7 +358,7 @@ class TimeFieldTest(TestCase): ...@@ -364,7 +358,7 @@ class TimeFieldTest(TestCase):
f.from_native('04:61:59') f.from_native('04:61:59')
except validators.ValidationError as e: except validators.ValidationError as e:
self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: "
"HH:MM; HH:MM:SS; HH:MM:SS.uuuuuu"]) "HH:MM[:ss[.uuuuuu]]"])
else: else:
self.fail("ValidationError was not properly raised") self.fail("ValidationError was not properly raised")
...@@ -378,7 +372,7 @@ class TimeFieldTest(TestCase): ...@@ -378,7 +372,7 @@ class TimeFieldTest(TestCase):
f.from_native('04 -- 31') f.from_native('04 -- 31')
except validators.ValidationError as e: except validators.ValidationError as e:
self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: " self.assertEqual(e.messages, ["Time has wrong format. Use one of these formats instead: "
"HH:MM; HH:MM:SS; HH:MM:SS.uuuuuu"]) "HH:MM[:ss[.uuuuuu]]"])
else: else:
self.fail("ValidationError was not properly raised") self.fail("ValidationError was not properly raised")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment