Add new ISO8601 setting + integration

This commit is contained in:
Stephan Groß 2013-03-01 16:24:25 +01:00
parent 7e702439eb
commit 29a54b5a77
4 changed files with 84 additions and 60 deletions

View File

@ -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'

View File

@ -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):
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):
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):
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):
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):
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):
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):

View File

@ -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 = {
# 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,
} }

View File

@ -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):
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):
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):
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):
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")