Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/api-guide/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,11 @@ Default: `['iso-8601']`

#### DURATION_FORMAT

A format string that should be used by default for rendering the output of `DurationField` serializer fields. If `None`, then `DurationField` serializer fields will return Python `timedelta` objects, and the duration encoding will be determined by the renderer.
Indicates the default format thath should be used for rendering the output of `DurationField` serializer fields. If `None`, then `DurationField` serializer fields will return Python `timedelta` objects, and the duration encoding will be determined by the renderer.

May be any of `None`, `'iso-8601'` or `'standard'` (the format accepted by `django.utils.dateparse.parse_duration`).
May be any of `None`, `'iso-8601'` or `'django'` (the format accepted by `django.utils.dateparse.parse_duration`).

Default: `'standard'`
Default: `'django'`

---

Expand Down
17 changes: 13 additions & 4 deletions rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1357,11 +1357,16 @@ def __init__(self, *, format=empty, **kwargs):
if format is not empty:
if format is None or (isinstance(format, str) and format.lower() in (ISO_8601, DJANGO_DURATION_FORMAT)):
self.format = format
else:
elif isinstance(format, str):
raise ValueError(
f"Unknown duration format provided, got '{format}'"
" while expecting 'django', 'iso-8601' or `None`."
)
else:
raise TypeError(
"duration format must be either str or `None`,"
f" not {type(format).__name__}"
)
super().__init__(**kwargs)
if self.max_value is not None:
message = lazy_format(self.error_messages['max_value'], max_value=self.max_value)
Expand Down Expand Up @@ -1396,9 +1401,13 @@ def to_representation(self, value):
if output_format.lower() == DJANGO_DURATION_FORMAT:
return duration_string(value)

raise ValueError(
f"Unknown duration format provided, got '{output_format}'"
" while expecting 'django', 'iso-8601' or `None`."
raise ValueError(
f"Unknown duration format provided, got '{output_format}'"
" while expecting 'django', 'iso-8601' or `None`."
)
raise TypeError(
"duration format must be either str or `None`,"
f" not {type(output_format).__name__}"
)


Expand Down
17 changes: 11 additions & 6 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1779,24 +1779,29 @@ def test_invalid_format(self):
"Unknown duration format provided, got 'unknown'"
" while expecting 'django', 'iso-8601' or `None`."
)
with pytest.raises(ValueError) as exc_info:
with pytest.raises(TypeError) as exc_info:
serializers.DurationField(format=123)
assert str(exc_info.value) == (
"Unknown duration format provided, got '123'"
" while expecting 'django', 'iso-8601' or `None`."
"duration format must be either str or `None`, not int"
)

@override_settings(REST_FRAMEWORK={'DURATION_FORMAT': 'unknown'})
def test_invalid_format_in_config(self):
field = serializers.DurationField()

with pytest.raises(ValueError) as exc_info:
field.to_representation(datetime.timedelta(days=1))
with override_settings(REST_FRAMEWORK={'DURATION_FORMAT': 'unknown'}):
with pytest.raises(ValueError) as exc_info:
field.to_representation(datetime.timedelta(days=1))

assert str(exc_info.value) == (
"Unknown duration format provided, got 'unknown'"
" while expecting 'django', 'iso-8601' or `None`."
)
with override_settings(REST_FRAMEWORK={'DURATION_FORMAT': 123}):
with pytest.raises(TypeError) as exc_info:
field.to_representation(datetime.timedelta(days=1))
assert str(exc_info.value) == (
"duration format must be either str or `None`, not int"
)


class TestNoOutputFormatDurationField(FieldValues):
Expand Down
Loading