8000 Default date/time fields now return python date/time objects again by… · dhepper/django-rest-framework@8adde50 · GitHub
[go: up one dir, main page]

Skip to content {"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}

Commit 8adde50

Browse files
committed
Default date/time fields now return python date/time objects again by default
1 parent 20fd738 commit 8adde50

File tree

7 files changed

+79
-28
lines changed

7 files changed

+79
-28
lines changed

docs/api-guide/fields.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ If you want to override this behavior, you'll need to declare the `DateTimeField
199199

200200
**Signature:** `DateTimeField(format=None, input_formats=None)`
201201

202-
* `format` - A string representing the output format. If not specified, the `DATETIME_FORMAT` setting will be used, which defaults to `'iso-8601'`.
202+
* `format` - A string representing the output format. If not specified, this defaults to `None`, which indicates that python `datetime` objects should be returned by `to_native`. In this case the datetime encoding will be determined by the renderer.
203203
* `input_formats` - A list of strings representing the input formats which may be used to parse the date. If not specified, the `DATETIME_INPUT_FORMATS` setting will be used, which defaults to `['iso-8601']`.
204204

205205
DateTime format strings may either be [python strftime formats][strftime] which explicitly specifiy the format, or the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style datetimes should be used. (eg `'2013-01-29T12:34:56.000000'`)
@@ -212,7 +212,7 @@ Corresponds to `django.db.models.fields.DateField`
212212

213213
**Signature:** `DateField(format=None, input_formats=None)`
214214

215-
* `format` - A string representing the output format. If not specified, the `DATE_FORMAT` setting will be used, which defaults to `'iso-8601'`.
215+
* `format` - A string representing the output format. If not specified, this defaults to `None`, which indicates that python `date` objects should be returned by `to_native`. In this case the date encoding will be determined by the renderer.
216216
* `input_formats` - A list of strings representing the input formats which may be used to parse the date. If not specified, the `DATE_INPUT_FORMATS` setting will be used, which defaults to `['iso-8601']`.
217217

218218
Date format strings may either be [python strftime formats][strftime] which explicitly specifiy the format, or the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style dates should be used. (eg `'2013-01-29'`)
@@ -227,7 +227,7 @@ Corresponds to `django.db.models.fields.TimeField`
227227

228228
**Signature:** `TimeField(format=None, input_formats=None)`
229229

230-
* `format` - A string representing the output format. If not specified, the `TIME_FORMAT` setting will be used, which defaults to `'iso-8601'`.
230+
* `format` - A string representing the output format. If not specified, this defaults to `None`, which indicates that python `time` objects should be returned by `to_native`. In this case the time encoding will be determined by the renderer.
231231
* `input_formats` - A list of strings representing the input formats which may be used to parse the date. If not specified, the `TIME_INPUT_FORMATS` setting will be used, which defaults to `['iso-8601']`.
232232

233233
Time format strings may either be [python strftime formats][strftime] which explicitly specifiy the format, or the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style times should be used. (eg `'12:34:56.000000'`)

docs/api-guide/settings.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,44 +192,56 @@ Default: `'format'`
192192

193193
---
194194

195-
## Date/Time formatting
195+
## Date and time formatting
196196

197197
*The following settings are used to control how date and time representations may be parsed and rendered.*
198198

199199
#### DATETIME_FORMAT
200200

201-
A format string that should be used by default for rendering the output of `DateTimeField` serializer fields.
201+
A format string that should be used by default for rendering the output of `DateTimeField` serializer fields. If `None`, then `DateTimeField` serializer fields will return python `datetime` objects, and the datetime encoding will be determined by the renderer.
202202

203-
Default: `'iso-8601'`
203+
May be any of `None`, `'iso-8601'` or a python [strftime format][strftime] string.
204+
205+
Default: `None'`
204206

205207
#### DATETIME_INPUT_FORMATS
206208

207209
A list of format strings that should be used by default for parsing inputs to `DateTimeField` serializer fields.
208210

211+
May be a list including the string `'iso-8601'` or python [strftime format][strftime] strings.
212+
209213
Default: `['iso-8601']`
210214

211215
#### DATE_FORMAT
212216

213-
A format string that should be used by default for rendering the output of `DateField` serializer fields.
217+
A format string that should be used by default for rendering the output of `DateField` serializer fields. If `None`, then `DateField` serializer fields will return python `date` objects, and the date encoding will be determined by the renderer.
214218

215-
Default: `'iso-8601'`
219+
May be any of `None`, `'iso-8601'` or a python [strftime format][strftime] string.
220+
221+
Default: `None`
216222

217223
#### DATE_INPUT_FORMATS
218224

219225
A list of format strings that should be used by default for parsing inputs to `DateField` serializer fields.
220226

227+
May be a list including the string `'iso-8601'` or python [strftime format][strftime] strings.
228+
221229
Default: `['iso-8601']`
222230

223231
#### TIME_FORMAT
224232

225-
A format string that should be used by default for rendering the output of `TimeField` serializer fields.
233+
A format string that should be used by default for rendering the output of `TimeField` serializer fields. If `None`, then `TimeField` serializer fields will return pyth 10000 on `time` objects, and the time encoding will be determined by the renderer.
234+
235+
May be any of `None`, `'iso-8601'` or a python [strftime format][strftime] string.
226236

227-
Default: `'iso-8601'`
237+
Default: `None`
228238

229239
#### TIME_INPUT_FORMATS
230240

231241
A list of format strings that should be used by default for parsing inputs to `TimeField` serializer fields.
232242

243+
May be a list including the string `'iso-8601'` or python [strftime format][strftime] strings.
244+
233245
Default: `['iso-8601']`
234246

235247
---
@@ -243,3 +255,4 @@ The name of a parameter in the URL conf that may be used to provide a format suf
243255
Default: `'format'`
244256

245257
[cite]: http://www.python.org/dev/peps/pep-0020/
258+
[strftime]: http://docs.python.org/2/library/time.html#time.strftime

rest_framework/fields.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ class DateField(WritableField):
494494
}
495495
empty = None
496496
input_formats = api_settings.DATE_INPUT_FORMATS
497-
format = api_settings.DATE_FORMAT
497+
format = None
498498

499499
def __init__(self, input_formats=None, format=None, *args, **kwargs):
500500
self.input_formats = input_formats if input_formats is not None else self.input_formats
@@ -536,8 +536,8 @@ def from_native(self, value):
536536
raise ValidationError(msg)
537537

538538
def to_native(self, value):
539-
if value is None:
540-
return None
539+
if value is None or self.format is None:
540+
return value
541541

542542
if isinstance(value, datetime.datetime):
543543
value = value.date()
@@ -557,7 +557,7 @@ class DateTimeField(WritableField):
557557
}
558558
empty = None
559559
input_formats = api_settings.DATETIME_INPUT_FORMATS
560-
format = api_settings.DATETIME_FORMAT
560+
format = None
561561

562562
def __init__(self, input_formats=None, format=None, *args, **kwargs):
563563
self.input_formats = input_formats if input_formats is not None else self.input_formats
@@ -605,8 +605,8 @@ def from_native(self, value):
605605
raise ValidationError(msg)
606606

607607
def to_native(self, value):
608-
if value is None:
609-
return None
608+
if value is None or self.format is None:
609+
return value
610610

611611
if self.format.lower() == ISO_8601:
612612
ret = value.isoformat()
@@ -626,7 +626,7 @@ class TimeField(WritableField):
626626
}
627627
empty = None
628628
input_formats = api_settings.TIME_INPUT_FORMATS
629-
format = api_settings.TIME_FORMAT
629+
format = None
630630

631631
def __init__(self, input_formats=None, format=None, *args, **kwargs):
632632
self.input_formats = input_formats if input_formats is not None else self.input_formats
@@ -661,8 +661,8 @@ def from_native(self, value):
661661
raise ValidationError(msg)
662662

663663
def to_native(self, value):
664-
if value is None:
665-
return None
664+
if value is None or self.format is None:
665+
return value
666666

667667
if isinstance(value, datetime.datetime):
668668
value = value.time()

rest_framework/tests/fields.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,22 @@ def test_from_native_invalid_format(self):
1 F438 53153

154154
def test_to_native(self):
155155
"""
156-
Make sure to_native() returns isoformat as default.
156+
Make sure to_native() returns datetime as default.
157157
"""
158158
f = serializers.DateField()
159159

160160
result_1 = f.to_native(datetime.date(1984, 7, 31))
161161

162+
self.assertEqual(datetime.date(1984, 7, 31), result_1)
163+
164+
def test_to_native_iso(self):
165+
"""
166+
Make sure to_native() with 'iso-8601' returns iso formated date.
167+
"""
168+
f = serializers.DateField(format='iso-8601')
169+
170+
result_1 = f.to_native(datetime.date(1984, 7, 31))
171+
162172
self.assertEqual('1984-07-31', result_1)
163173

164174
def test_to_native_custom_format(self):
@@ -289,6 +299,22 @@ def test_to_native(self):
289299
result_3 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
290300
result_4 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
291301

302+
self.assertEqual(datetime.datetime(1984, 7, 31), result_1)
303+
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31), result_2)
304+
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59), result_3)
305+
self.assertEqual(datetime.datetime(1984, 7, 31, 4, 31, 59, 200), result_4)
306+
307+
def test_to_native_iso(self):
308+
"""
309+
Make sure to_native() with format=iso-8601 returns iso formatted datetime.
310+
"""
311+
f = serializers.DateTimeField(format='iso-8601')
312+
313+
result_1 = f.to_native(datetime.datetime(1984, 7, 31))
314+
result_2 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31))
315+
result_3 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59))
316+
result_4 = f.to_native(datetime.datetime(1984, 7, 31, 4, 31, 59, 200))
317+
292318
self.assertEqual('1984-07-31T00:00:00', result_1)
293319
self.assertEqual('1984-07-31T04:31:00', result_2)
294320
self.assertEqual('1984-07-31T04:31:59', result_3)
@@ -419,13 +445,26 @@ def test_from_native_invalid_format(self):
419445

420446
def test_to_native(self):
421447
"""
422-
Make sure to_native() returns isoformat as default.
448+
Make sure to_native() returns time object as default.
423449
"""
424450
f = serializers.TimeField()
425451
result_1 = f.to_native(datetime.time(4, 31))
426452
result_2 = f.to_native(datetime.time(4, 31, 59))
427453
result_3 = f.to_native(datetime.time(4, 31, 59, 200))
428454

455+
self.assertEqual(datetime.time(4, 31), result_1)
456+
self.assertEqual(datetime.time(4, 31, 59), result_2)
457+
self.assertEqual(datetime.time(4, 31, 59, 200), result_3)
458+
459+
def test_to_native_iso(self):
460+
"""
461+
Make sure to_native() with format='iso-8601' returns iso formatted time.
462+
"""
463+
f = serializers.TimeField(format='iso-8601')
464+
result_1 = f.to_native(datetime.time(4, 31))
465+
result_2 = f.to_native(datetime.time(4, 31, 59))
466+
result_3 = f.to_native(datetime.time(4, 31, 59, 200))
467+
429468
self.assertEqual('04:31:00', result_1)
430469
self.assertEqual('04:31:59', result_2)
431470
self.assertEqual('04:31:59.000200', result_3)

rest_framework/tests/filterset.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def setUp(self):
6565

6666
self.objects = FilterableItem.objects
6767
self.data = [
68-
{'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date.isoformat()}
68+
{'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date}
6969
for obj in self.objects.all()
7070
]
7171

@@ -95,7 +95,7 @@ def test_get_filtered_fields_root_view(self):
9595
request = factory.get('/?date=%s' % search_date) # search_date str: '2012-09-22'
9696
response = view(request).render()
9797
self.assertEqual(response.status_code, status.HTTP_200_OK)
98-
expected_data = [f for f in self.data if datetime.datetime.strptime(f['date'], '%Y-%m-%d').date() == search_date]
98+
expected_data = [f for f in self.data if f['date'] == search_date]
9999
self.assertEqual(response.data, expected_data)
100100

101101
@unittest.skipUnless(django_filters, 'django-filters not installed')
@@ -125,7 +125,7 @@ def test_get_filtered_class_root_view(self):
125125
request = factory.get('/?date=%s' % search_date) # search_date str: '2012-10-02'
126126
response = view(request).render()
127127
self.assertEqual(response.status_code, status.HTTP_200_OK)
128-
expected_data = [f for f in self.data if datetime.datetime.strptime(f['date'], '%Y-%m-%d').date() > search_date]
128+
expected_data = [f for f in self.data if f['date'] > search_date]
129129
self.assertEqual(response.data, expected_data)
130130

131131
# Tests that the text filter set with 'icontains' in the filter class works.
@@ -142,8 +142,7 @@ def test_get_filtered_class_root_view(self):
142142
request = factory.get('/?decimal=%s&date=%s' % (search_decimal, search_date))
143143
response = view(request).render()
144144
self.assertEqual(response.status_code, status.HTTP_200_OK)
145-
expected_data = [f for f in self.data if
146-
datetime.datetime.strptime(f['date'], '%Y-%m-%d').date() > search_date and
145+
expected_data = [f for f in self.data if f['date'] > search_date and
147146
f['decimal'] < search_decimal]
148147
self.assertEqual(response.data, expected_data)
149148

rest_framework/tests/pagination.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def setUp(self):
102102

103103
self.objects = FilterableItem.objects
104104
self.data = [
105-
{'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date.isoformat()}
105+
{'id': obj.id, 'text': obj.text, 'decimal': obj.decimal, 'date': obj.date}
106106
for obj in self.objects.all()
107107
]
108108

rest_framework/tests/serializer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def setUp(self):
112112
self.expected = {
113113
'email': 'tom@example.com',
114114
'content': 'Happy new year!',
115-
'created': '2012-01-01T00:00:00',
115+
'created': datetime.datetime(2012, 1, 1),
116116
'sub_comment': 'And Merry Christmas!'
117117
}
118118
self.person_data = {'name': 'dwight', 'age': 35}

0 commit comments

Comments
 (0)
0