How to store variable timedeltas in a Django model?

750 views
Skip to first unread message

Karen Rustad

unread,
Aug 14, 2011, 1:10:25 AM8/14/11
to Django users, ash...@asheesh.org
Hello all,

In one of my models, I want to store a timedelta--a length of time not
tied to a particular start and end date. Although timedeltas are built
into Python, tragically there's no TimeDeltaField in Django.

Extra complications:

* The timedelta can be quite large -- on the scale of one week to
several months.
* The timedelta has a default value, but it can be changed by the
administrator.
* I want the default timedelta length to be one month (which, of
course, has a variable number of days!)

It seems like *someone* has to have been able to do this, if only as a
custom model field. But I wasn't able to find anything in the archives
on this list and the #django IRC logger down so I couldn't search
that. :/

I did read the docs on how to write a custom model, but it looks
terribly confusing--it's not clear which or how many of the attributes
mentioned in the docs I would need to customize, given that it *is* a
built-in Python variable type, and I have exactly zero experience
dealing with databases directly.

If anyone's got a hack around this limitation to recommend, or even
some more relevant sample code than what's in the custom model docs,
that would be super helpful!

-- Karen

Python_Junkie

unread,
Aug 14, 2011, 9:13:55 AM8/14/11
to Django users
One of the reasons that I migrated to django is because of the
underlying functionality.. With that said I would use a separate table
or file, whichever you are comfortable with , to store the changing
time delta variable.

You could dynamically retrieve this variable in the view or, the
example that django provides is to create a function in the models.py
and call that function from the model that you wanted to use the time
delta

https://docs.djangoproject.com/en/1.3/topics/db/managers/

The code on this page that I am referring to is:

class PollManager(models.Manager):
def with_counts(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute("""
SELECT p.id, p.question, p.poll_date, COUNT(*)
FROM polls_opinionpoll p, polls_response r
WHERE p.id = r.poll_id
GROUP BY 1, 2, 3
ORDER BY 3 DESC""")
result_list = []
for row in cursor.fetchall():
p = self.model(id=row[0], question=row[1],
poll_date=row[2])
p.num_responses = row[3]
result_list.append(p)
return result_list

class OpinionPoll(models.Model):
question = models.CharField(max_length=200)
poll_date = models.DateField()
objects = PollManager()
******************************************

The function that you want would be repalced with the much simpler sql

select timedelta from time_delta ##table

Rafael Durán Castañeda

unread,
Aug 14, 2011, 1:11:13 PM8/14/11
to django...@googlegroups.com
Check this http://dpaste.com/594215/

I've taken it from Marty Alchin's 'Pro Django' book and I just fixed
decimal import to get it working

Subhranath Chunder

unread,
Aug 14, 2011, 2:57:38 PM8/14/11
to django...@googlegroups.com
You can something like the following code to create a custom TimeDeltaField in django.
Here I'm using python object serialization of represent the object as a character object in the database.


models.py
=======
import datetime
import pickle
from django.db import models

class TimeDeltaField(models.Field):
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 200
        if 'default' in kwargs:
            kwargs['default'] = pickle.dumps(kwargs['default'])
        super(TimeDeltaField, self).__init__(*args, **kwargs)

    def get_internal_type(self):
        return 'CharField'

    def to_python(self, value):
        if isinstance(value, basestring):
            return pickle.loads(str(value))
        return value

    def get_prep_value(self, value):
        return pickle.dumps(value)

class MyModel(models.Model):
    timedelta = TimeDeltaField(default=datetime.timedelta(days=30))

    def __unicode__(self):
        return unicode(self.id)

=======

This will enable you to use API like:

MyModel.objects.create()
MyModel.objects.create(datetime.timedelta(days=10, seconds=90))

I, guess you can now work on the so called "extra complications". :)

Thanks,
Subhranath Chunder.



--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.




Doug Ballance

unread,
Aug 14, 2011, 7:30:24 PM8/14/11
to Django users
Depending on the resolution and maximum duration, you could just use
an integerfield containing either the number of seconds or minutes,
and then recreate it. That way you can also base queries off of the
value, which you can't do with just a pickle field. Of you could
subclass the integerfield and make it accept/return timdelta objects
similar to how the pickled version is above.

The max duration depends on the data type in your database backend.
Postgres I think is +/- -214748364 or so. If you use a resolution of
seconds, that is a limit of about 68 years. Using minute resolution
would be about 4 millenia.

Matt Schinckel

unread,
Aug 14, 2011, 7:48:01 PM8/14/11
to django...@googlegroups.com, ash...@asheesh.org
I've also created a TimeDeltaField.

It stores internally in PG as an INTERVAL, but as a string in other dbs.


Matt.

Derek

unread,
Aug 15, 2011, 11:00:53 AM8/15/11
to Django users
Perhaps all those that contributed code can add their contributions
to:
http://djangosnippets.org/
Where it will be centrally accessible, searchable etc etc.
Reply all
Reply to author
Forward
0 new messages