mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 01:47:59 +03:00 
			
		
		
		
	Add new ISO8601 setting + integration
This commit is contained in:
		
							parent
							
								
									7e702439eb
								
							
						
					
					
						commit
						29a54b5a77
					
				| 
						 | 
				
			
			@ -4,3 +4,6 @@ VERSION = __version__  # synonym
 | 
			
		|||
 | 
			
		||||
# Header encoding (see RFC5987)
 | 
			
		||||
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 import forms
 | 
			
		||||
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.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from rest_framework import ISO8601
 | 
			
		||||
from rest_framework.compat import timezone
 | 
			
		||||
from rest_framework.compat import BytesIO
 | 
			
		||||
from rest_framework.compat import six
 | 
			
		||||
| 
						 | 
				
			
			@ -472,21 +474,30 @@ class DateField(WritableField):
 | 
			
		|||
            return value
 | 
			
		||||
 | 
			
		||||
        for format in self.input_formats:
 | 
			
		||||
            try:
 | 
			
		||||
                parsed = datetime.datetime.strptime(value, format)
 | 
			
		||||
            except (ValueError, TypeError):
 | 
			
		||||
                pass
 | 
			
		||||
            if format.lower() == ISO8601:
 | 
			
		||||
                try:
 | 
			
		||||
                    parsed = parse_date(value)
 | 
			
		||||
                except (ValueError, TypeError):
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    if parsed is not None:
 | 
			
		||||
                        return parsed
 | 
			
		||||
            else:
 | 
			
		||||
                return parsed.date()
 | 
			
		||||
                try:
 | 
			
		||||
                    parsed = datetime.datetime.strptime(value, format)
 | 
			
		||||
                except (ValueError, TypeError):
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    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)
 | 
			
		||||
        raise ValidationError(msg)
 | 
			
		||||
 | 
			
		||||
    def to_native(self, value):
 | 
			
		||||
        if self.output_format is not None:
 | 
			
		||||
            return value.strftime(self.output_format)
 | 
			
		||||
        return value.isoformat()
 | 
			
		||||
        if self.output_format.lower() == ISO8601:
 | 
			
		||||
            return value.isoformat()
 | 
			
		||||
        return value.strftime(self.output_format)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DateTimeField(WritableField):
 | 
			
		||||
| 
						 | 
				
			
			@ -525,21 +536,30 @@ class DateTimeField(WritableField):
 | 
			
		|||
            return value
 | 
			
		||||
 | 
			
		||||
        for format in self.input_formats:
 | 
			
		||||
            try:
 | 
			
		||||
                parsed = datetime.datetime.strptime(value, format)
 | 
			
		||||
            except (ValueError, TypeError):
 | 
			
		||||
                pass
 | 
			
		||||
            if format.lower() == ISO8601:
 | 
			
		||||
                try:
 | 
			
		||||
                    parsed = parse_datetime(value)
 | 
			
		||||
                except (ValueError, TypeError):
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    if parsed is not None:
 | 
			
		||||
                        return parsed
 | 
			
		||||
            else:
 | 
			
		||||
                return parsed
 | 
			
		||||
                try:
 | 
			
		||||
                    parsed = datetime.datetime.strptime(value, format)
 | 
			
		||||
                except (ValueError, TypeError):
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    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)
 | 
			
		||||
        raise ValidationError(msg)
 | 
			
		||||
 | 
			
		||||
    def to_native(self, value):
 | 
			
		||||
        if self.output_format is not None:
 | 
			
		||||
            return value.strftime(self.output_format)
 | 
			
		||||
        return value.isoformat()
 | 
			
		||||
        if self.output_format.lower() == ISO8601:
 | 
			
		||||
            return value.isoformat()
 | 
			
		||||
        return value.strftime(self.output_format)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TimeField(WritableField):
 | 
			
		||||
| 
						 | 
				
			
			@ -565,21 +585,30 @@ class TimeField(WritableField):
 | 
			
		|||
            return value
 | 
			
		||||
 | 
			
		||||
        for format in self.input_formats:
 | 
			
		||||
            try:
 | 
			
		||||
                parsed = datetime.datetime.strptime(value, format)
 | 
			
		||||
            except (ValueError, TypeError):
 | 
			
		||||
                pass
 | 
			
		||||
            if format.lower() == ISO8601:
 | 
			
		||||
                try:
 | 
			
		||||
                    parsed = parse_time(value)
 | 
			
		||||
                except (ValueError, TypeError):
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    if parsed is not None:
 | 
			
		||||
                        return parsed
 | 
			
		||||
            else:
 | 
			
		||||
                return parsed.time()
 | 
			
		||||
                try:
 | 
			
		||||
                    parsed = datetime.datetime.strptime(value, format)
 | 
			
		||||
                except (ValueError, TypeError):
 | 
			
		||||
                    pass
 | 
			
		||||
                else:
 | 
			
		||||
                    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)
 | 
			
		||||
        raise ValidationError(msg)
 | 
			
		||||
 | 
			
		||||
    def to_native(self, value):
 | 
			
		||||
        if self.output_format is not None:
 | 
			
		||||
            return value.strftime(self.output_format)
 | 
			
		||||
        return value.isoformat()
 | 
			
		||||
        if self.output_format.lower() == ISO8601:
 | 
			
		||||
            return value.isoformat()
 | 
			
		||||
        return value.strftime(self.output_format)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IntegerField(WritableField):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,8 +18,11 @@ REST framework settings, checking for user settings first, then falling
 | 
			
		|||
back to the defaults.
 | 
			
		||||
"""
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.utils import importlib
 | 
			
		||||
 | 
			
		||||
from rest_framework import ISO8601
 | 
			
		||||
from rest_framework.compat import six
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -79,24 +82,19 @@ DEFAULTS = {
 | 
			
		|||
 | 
			
		||||
    # Input and output formats
 | 
			
		||||
    'DATE_INPUT_FORMATS': (
 | 
			
		||||
        '%Y-%m-%d',     # '1984-07-31'
 | 
			
		||||
        ISO8601,
 | 
			
		||||
    ),
 | 
			
		||||
    'DATE_OUTPUT_FORMAT': None,
 | 
			
		||||
    'DATE_OUTPUT_FORMAT': ISO8601,
 | 
			
		||||
 | 
			
		||||
    'DATETIME_INPUT_FORMATS': (
 | 
			
		||||
        '%Y-%m-%d',              # '1984-07-31'
 | 
			
		||||
        '%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'
 | 
			
		||||
        ISO8601,
 | 
			
		||||
    ),
 | 
			
		||||
    'DATETIME_OUTPUT_FORMAT': None,
 | 
			
		||||
    'DATETIME_OUTPUT_FORMAT': ISO8601,
 | 
			
		||||
 | 
			
		||||
    'TIME_INPUT_FORMATS': (
 | 
			
		||||
        '%H:%M',        # '04:31'
 | 
			
		||||
        '%H:%M:%S',     # '04:31:59'
 | 
			
		||||
        '%H:%M:%S.%f',  # '04:31:59.000200'
 | 
			
		||||
        ISO8601,
 | 
			
		||||
    ),
 | 
			
		||||
    'TIME_OUTPUT_FORMAT': None,
 | 
			
		||||
    'TIME_OUTPUT_FORMAT': ISO8601,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -173,30 +173,26 @@ class DateTimeFieldTest(TestCase):
 | 
			
		|||
        Make sure from_native() accepts default iso input formats.
 | 
			
		||||
        """
 | 
			
		||||
        f = serializers.DateTimeField()
 | 
			
		||||
        result_1 = f.from_native('1984-07-31')
 | 
			
		||||
        result_2 = f.from_native('1984-07-31 04:31')
 | 
			
		||||
        result_3 = f.from_native('1984-07-31 04:31:59')
 | 
			
		||||
        result_4 = f.from_native('1984-07-31 04:31:59.000200')
 | 
			
		||||
        result_1 = 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.000200')
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(datetime.datetime(1984, 7, 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_3)
 | 
			
		||||
        self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_4)
 | 
			
		||||
        self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_1)
 | 
			
		||||
        self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_2)
 | 
			
		||||
        self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_3)
 | 
			
		||||
 | 
			
		||||
    def test_from_native_datetime_datetime(self):
 | 
			
		||||
        """
 | 
			
		||||
        Make sure from_native() accepts a datetime.datetime instance.
 | 
			
		||||
        """
 | 
			
		||||
        f = serializers.DateTimeField()
 | 
			
		||||
        result_1 = f.from_native(datetime.datetime(1984, 7, 31))
 | 
			
		||||
        result_2 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31))
 | 
			
		||||
        result_3 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
 | 
			
		||||
        result_4 = f.from_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
 | 
			
		||||
        result_1 = 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, 200))
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(result_1, datetime.datetime(1984, 7, 31))
 | 
			
		||||
        self.assertEqual(result_2, datetime.datetime(1984, 7, 31, 4, 31))
 | 
			
		||||
        self.assertEqual(result_3, datetime.datetime(1984, 7, 31, 4, 31, 59))
 | 
			
		||||
        self.assertEqual(result_4, datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
 | 
			
		||||
        self.assertEqual(result_1, 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, 200))
 | 
			
		||||
 | 
			
		||||
    def test_from_native_custom_format(self):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -239,8 +235,7 @@ class DateTimeFieldTest(TestCase):
 | 
			
		|||
            f.from_native('04:61:59')
 | 
			
		||||
        except validators.ValidationError as e:
 | 
			
		||||
            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"])
 | 
			
		||||
                                          "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"])
 | 
			
		||||
        else:
 | 
			
		||||
            self.fail("ValidationError was not properly raised")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -254,8 +249,7 @@ class DateTimeFieldTest(TestCase):
 | 
			
		|||
            f.from_native('04 -- 31')
 | 
			
		||||
        except validators.ValidationError as e:
 | 
			
		||||
            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"])
 | 
			
		||||
                                          "YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]"])
 | 
			
		||||
        else:
 | 
			
		||||
            self.fail("ValidationError was not properly raised")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -364,7 +358,7 @@ class TimeFieldTest(TestCase):
 | 
			
		|||
            f.from_native('04:61:59')
 | 
			
		||||
        except validators.ValidationError as e:
 | 
			
		||||
            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:
 | 
			
		||||
            self.fail("ValidationError was not properly raised")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +372,7 @@ class TimeFieldTest(TestCase):
 | 
			
		|||
            f.from_native('04 -- 31')
 | 
			
		||||
        except validators.ValidationError as e:
 | 
			
		||||
            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:
 | 
			
		||||
            self.fail("ValidationError was not properly raised")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user