twomed
twomed

Reputation: 135

TimeField and DurationField int error

I have run into this error when running python manage.py migrate when using DurationField and TimeField both give me a:

return int(round(value.total_seconds() * 1000000))
AttributeError: 'int' object has no attribute 'total_seconds'

I have seen this error on this site but only for a Django 1.8. Currently, I am using Django 1.10. I have tried these suggesions :

DurationField(default=timedelta()), 
DurationField(), 
DurationField(default=timedelta()), 
DurationField(default=int(timedelta(minutes=20).total_seconds())). 

My model currently looks like:

class SomeModel(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    lunchnumber = models.IntegerField(null=True, blank=True)
    role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES,null=True, blank=True)
    breaktime = models.DurationField(default=timedelta(minutes=45))

    def to_python(self, value):
        if value is None:
            return value
        if isinstance(value, datetime.timedelta):
            return value
        try:
            parsed = parse_duration(value)
        except ValueError:
            pass
        else:
            if parsed is not None:
                return parsed

Addressing Prakhar Trivedi's question: I do not know what value is not working well. I was under the assumption it was the default value that django is trying populate that database table with. I am under this impression because of .......in get_db_prep_value return int(round(value.total_seconds() * 1000000)) AttributeError: 'int' object has no attribute 'total_seconds'

Addressing iklinac's Answer:

I went in and added the default=timedelta(minutes=45). I do have it imported from datetime But I feel I am missing something. I am very new at this and have not seen a to_python function. What am I missing I am still getting the same error?

Upvotes: 0

Views: 3070

Answers (2)

cjwn
cjwn

Reputation: 11

I have quite the same problem, and iklinac's Answer helped me.

Once I ran the python manage.py makemigrations and showing

You are trying to change the nullable field 'duration' on task to non-nullable without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)
 3) Quit, and let me add a default in models.py

So I set a 0 to the DurationField cause of laziness...

after that the error keeps showing...

By seen this answer I found that when running "python manage.py migrate" it actually running a 000x_auto_xxxx.py in the folder named migrations. so I found that .py file which contained the field=models.DurationField(default=0) and change it to the right way, and finally solve the problem.

Hope this may help

Upvotes: 0

iklinac
iklinac

Reputation: 15728

Please check if you are importing timedelta from datetime package :)

from datetime import timedelta

These two should work

DurationField(default=timedelta(minutes=20))
DurationField(default=timedelta())

to_python function of DurationField is following

    if value is None:
        return value
    if isinstance(value, datetime.timedelta):
        return value
    try:
        parsed = parse_duration(value)
    except ValueError:
        pass
    else:
        if parsed is not None:
            return parsed

If you are still having troubles with timedelta you could use one of these formats as stated in parse_duration code comments

def parse_duration(value):
    """Parses a duration string and returns a datetime.timedelta.

    The preferred format for durations in Django is '%d %H:%M:%S.%f'.

    Also supports ISO 8601 representation.
    """
    match = standard_duration_re.match(value)
    if not match:
        match = iso8601_duration_re.match(value)
    if match:
        kw = match.groupdict()
        if kw.get('microseconds'):
            kw['microseconds'] = kw['microseconds'].ljust(6, '0')
        kw = {k: float(v) for k, v in six.iteritems(kw) if v is not None}
        return datetime.timedelta(**kw)

Upvotes: 1

Related Questions