Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Duration Field with negative value

Tags:

python

django

I have a model which contains a DurationField. If positive values are saved in this field, I get the correct result, if negative values are saved it returns "None" if I'm trying to access the attribute of the model.

The model looks like the following:

class Calendar(models.Model):
    nominal_actual_comparison = models.DurationField(null=True,blank = True)

If I'm trying to access it now within a view like the following and the value is negative I'm obtaining a NoneType object:

calendar_object = Calendar.objects.get(id = 1)
calendar_object.nominal_actual_comparison

I looked into the database and saw, that the DurationField is saved as a BigInt. The values in the database are definitely correct, therefore I'm wondering if there is a bug in the implementation of the DurationField or am I doing something wrong? What can I do instead? Is it possible to overwrite the DurationField class to adapt the way how the BigInt gets converted into a datetime.timedelta object? I saw a method called to_python which apparently calls a parse_duration method, but the to_python method is somehow never getting called !? I hope you can help me, thanks in advance!

like image 412
mitcon_mario Avatar asked Dec 03 '15 15:12

mitcon_mario


1 Answers

I solved this issue in the meantime by overriding the DurationField class. I had to handle the conversion of the BigInt on my own, therefore I had to overwrite the get_db_converters method because in the original DurationField it calls a method parse_datetime which isn't capable of handling negative values obviously. Moreover I had to overwrite from_db_value to implement my own conversion of the database value. The code of my DurationField looks like the following now:

class DurationField(DurationField):

def get_db_converters(self, connection):
    if hasattr(self, 'from_db_value'):
        return [self.from_db_value]
    return []


def from_db_value(self, value, expression, connection, context):
    result = ""

    if (value != None):
        d = str(decimal.Decimal(value) / decimal.Decimal(1000000))
        try:
            sec = d.split(".")[0]
            micro_sec = d.split(".")[1]
        except IndexError:
            sec = int(d)
            micro_sec = 0

        result = self.convertSecondsToTimeDelta(seconds = sec, microseconds = micro_sec)
        return result
    else:
        return None

def convertSecondsToTimeDelta(self, seconds = 0 , microseconds = 0):
    return datetime.timedelta(seconds = seconds, microseconds = microseconds)
like image 73
mitcon_mario Avatar answered Nov 16 '22 16:11

mitcon_mario