Reputation: 113
I have extended datetime.timedelta for some previous work to update the division operator to support floats (not supported before python 3.x). Having started using a DurationField in one of my models I would like to create a custom version which uses my extended timedelta class so that objects returned after a query include my custom timedelta class. What is the correct approach to implement this?
I've been editing the DurationField class itself whilst I figure out how to do the above before taking the next step to figure out how to add a custom model field. Code as follows (modified Django source code:
class TimeDeltaExtended(datetime.timedelta):
def __div__(self, divisor):
return TimeDeltaExtended(seconds=self.total_seconds()/divisor)
def __mul__(self, multiplier):
return TimeDeltaExtended(seconds=self.total_seconds()*multiplier)
def __add__(self, other):
if isinstance(other, int) and other is 0:
return self
else:
datetime.timedelta.__add__(other)
class DurationField(Field):
...
def to_python(self, value):
if value is None:
return value
if isinstance(value, TimeDeltaExtended):
return value
try:
parsed = parse_duration(value)
except ValueError:
pass
else:
if parsed is not None:
return parsed
raise exceptions.ValidationError(
self.error_messages['invalid'],
code='invalid',
params={'value': value},
)
...
However when I use this code queries still return normal TimeDelta objects. Is this even the area I should be looking at?
Environment Python 2.7, Django 1.11
Upvotes: 2
Views: 537
Reputation: 362487
This is how duration field will parse the serialised form of timedelta(seconds=123.456)
:
>>> DurationField().to_python('00:02:03.456000')
datetime.timedelta(0, 123, 456000)
You can just let the superclass do the heavy lifting of validation, exception handling, etc. Just convert to your specialised class as a post-processing step:
>>> class MyDurationField(DurationField):
... def to_python(self, value):
... timedelta = super(MyDurationField, self).to_python(value)
... return TimeDeltaExtended(seconds=timedelta.total_seconds())
...
>>> MyDurationField().to_python('00:02:03.456000')
TimeDeltaExtended(0, 123, 456000)
>>> MyDurationField().to_python('00:02:03.456000') / 2.0
TimeDeltaExtended(0, 61, 728000)
Upvotes: 1