-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
DurationField output format #8532
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
docs/api-guide/fields.md
Outdated
- `max_value` Validate that the duration provided is no greater than this value. | ||
- `min_value` Validate that the duration provided is no less than this value. | ||
|
||
#### `DurationField` format strings | ||
Format strings may either be the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style intervals should be used (eg `'P4DT1H15M20S'`), or the special string `'standard'`, which indicates that Django interval format `'[DD] [HH:[MM:]]ss[.uuuuuu]'` hould be used (eg: `'4 1:15:20'`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Format strings may either be the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style intervals should be used (eg `'P4DT1H15M20S'`), or the special string `'standard'`, which indicates that Django interval format `'[DD] [HH:[MM:]]ss[.uuuuuu]'` hould be used (eg: `'4 1:15:20'`). | |
Format strings may either be the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style intervals should be used (eg `'P4DT1H15M20S'`), or the special string `'standard'`, which indicates that Django interval format `'[DD] [HH:[MM:]]ss[.uuuuuu]'` should be used (eg: `'4 1:15:20'`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the typo 😅
I have fixed it locally, will update as soon as I have other elements to push because I would like to keep the history clear without having to perform too many rebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. (Incidentally, all pull requests are squashed, so that doesn't matter at all from my perspective.)
|
||
#### 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
None
, thenDurationField
serializer fields will return Pythontimedelta
objects, and the duration encoding will be determined by the renderer.
What output style does this produce with the current JSONRenderer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the current JSONRenderer
, which uses JSONEncoder
it will output the string value of "total seconds" (doc).
django-rest-framework/rest_framework/utils/encoders.py
Lines 39 to 40 in 129890a
elif isinstance(obj, datetime.timedelta): | |
return str(obj.total_seconds()) |
Using the same example value will be:
from datetime import timedelta
d = timedelta(days=4, hours=1, minutes=15, seconds=20)
print(str(d.total_seconds())
# 350120.0
Thanks - good to talk this through from a docs-first perspective. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Can we reopen this? |
I think it's not possible to contribute to the pr to solve the conflicts, @sevdog would you be able to do it? |
Just rebased the PR, the "conflict" was a very silly issue in the doc file 🤷♂️ CI is failing due to a change in django-main branch, it should be addressed in an other PR. |
295a462
to
70751a5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw FAILED tests/test_fields.py::TestISOOutputFormatDurationField::test_outputs
=========== 1 failed,
Ok, fixed the test. It was a long lasting double typo (wrong class and wrong format). |
we should merge this only in a major release |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
The fix seems still relevant. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this will be accepted or not, but if it is accepted, fixing the merge conflict should be enough
Conflict revolved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for resolving the conflict; some more comments here!
* `format` - A string representing the output format. If not specified, this defaults to the same value as the `DURATION_FORMAT` settings key, which will be `'standard'` unless set. Setting to a format string indicates that `to_representation` return values should be coerced to string output. Format strings are described below. Setting this value to `None` indicates that Python `timedelta` objects should be returned by `to_representation`. In this case the date encoding will be determined by the renderer. | ||
* `max_value` Validate that the duration provided is no greater than this value. | ||
* `min_value` Validate that the duration provided is no less than this value. | ||
|
||
#### `DurationField` format strings | ||
Format strings may either be the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style intervals should be used (eg `'P4DT1H15M20S'`), or the special string `'standard'`, which indicates that Django interval format `'[DD] [HH:[MM:]]ss[.uuuuuu]'` should be used (eg: `'4 1:15:20'`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the use of the term "format string" very confusing here. The term means something else in Python, referring to string with placeholder variables that get filled in. That sounds like one could set format="%h:%m:%s"
to get the duration in hours, minutes, seconds, but that is not the case. Please find another word, like "format family", "format variety", ... or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, how about format_name
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used the "format" name just to keep uniformity with date/time fields, because to me it looked more elegant.
Since there is nothing like strftime/strptime for timedelta
this may also just be a flag if it is clear/readable enough.
@@ -21,6 +21,7 @@ | |||
|
|||
# Default datetime input and output formats | |||
ISO_8601 = 'iso-8601' | |||
STD_DURATION = 'standard' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out that this value isn't used anywhere; as long as format
is set to anything else but ISO_8601
, we end up with 'standard'
behavior.
That's probably not intended. Can this be correct? Let's also add a test case for the behavior with an unknown format
value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That value was placed just to be a placeholder for the default format. It may just be set to None
in settings.py
. I added the "standard" after this conversation just to improve readability. The format-as-ISO may also be a flag, however that pattern may be harder to read and would add a non-uniformity with other time-related fields.
It is true that django itself does not provide much flexibility with duration representation, which also comes from stdlib timedelta
which has no implementation with to-str or from-str like date/time does.
Which way do you prefer for completing this?
@@ -1351,9 +1351,11 @@ class DurationField(Field): | |||
'overflow': _('The number of days must be between {min_days} and {max_days}.'), | |||
} | |||
|
|||
def __init__(self, **kwargs): | |||
def __init__(self, format=empty, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should disallow specifying this as positional argument: DurationField('iso-8601')
(we don't want that).
All other options come from the **kwargs
...
valid_inputs = {} | ||
invalid_inputs = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to add test coverage for parsing duration in ISO format, as I would expect it to work both ways
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently the parse_duration
method of django, which is used inside DurationField
, already parses ISO-8601 format and the format specific to postgres by its own.
This could be added to the TestDurationField
testcase.
Where do you prefer these tests to be added?
PS:
From this point of view the current error message "Use one of these formats instead: [DD] [HH:[MM:]]ss[.uuuuuu]"
is not (completely) right, however changing it would be a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure where that an extension of this error message should be considered a breaking change; the wording "one of" already hints that the application should not rely the one specific format being given in the message.
* `format` - A string representing the output format. If not specified, this defaults to the same value as the `DURATION_FORMAT` settings key, which will be `'standard'` unless set. Setting to a format string indicates that `to_representation` return values should be coerced to string output. Format strings are described below. Setting this value to `None` indicates that Python `timedelta` objects should be returned by `to_representation`. In this case the date encoding will be determined by the renderer. | ||
* `max_value` Validate that the duration provided is no greater than this value. | ||
* `min_value` Validate that the duration provided is no less than this value. | ||
|
||
#### `DurationField` format strings | ||
Format strings may either be the special string `'iso-8601'`, which indicates that [ISO 8601][iso8601] style intervals should be used (eg `'P4DT1H15M20S'`), or the special string `'standard'`, which indicates that Django interval format `'[DD] [HH:[MM:]]ss[.uuuuuu]'` should be used (eg: `'4 1:15:20'`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, how about format_name
?
Co-authored-by: Bruno Alla <[email protected]>
Co-authored-by: Bruno Alla <[email protected]>
Description
As explained in #8527 this PR will provide the ability to choose the output format for
DurationFields
.Since Python builtim
timedelta
object does not have any format function we are going to allow only formats which are already defined in Django codebase in the packagedjango.utils.duration
:duration_string
duration_iso_string