Add more precise validation check for duration field format and adjust docs

This commit is contained in:
sevdog 2025-08-08 10:03:14 +02:00
parent a3096b9989
commit aae5465700
No known key found for this signature in database
GPG Key ID: D939AF7A93A9C178
3 changed files with 27 additions and 13 deletions

View File

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

View File

@ -1357,11 +1357,16 @@ class DurationField(Field):
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)
@ -1396,9 +1401,13 @@ class DurationField(Field):
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__}"
)

View File

@ -1779,24 +1779,29 @@ class TestDurationField(FieldValues):
"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):