mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-26 11:33:59 +03:00
Add new ISO8601 setting + integration
This commit is contained in:
parent
a9d36d4726
commit
9c964cf37b
|
@ -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'
|
|
@ -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):
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user