Django timedelta custom model field (with full example)

by Subhranath Chunder

This intends to show a full working example of a django custom model field.

TimeDeltaField uses python object serialization or namely pickle, to store a datetime.timedelta type native python object on a database in the form of character data. This example implements only the must-have elements for it's working.

import datetime
import pickle
from django.db import models

class TimeDeltaField(models.Field):
    """Custom model field to store python native datetime.timedelta
    object in database, in serialized form.
    """
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        # Set the max_length to something long enough to store the data
        # in string format.
        kwargs['max_length'] = 200

        # Make sure the default specified is also serialized, else the
        # objects own string representation would be used.
        if 'default' in kwargs:
            kwargs['default'] = pickle.dumps(kwargs['default'])

        super(TimeDeltaField, self).__init__(*args, **kwargs)

    def get_internal_type(self):
        # Store the serialized data as the default 'CharField' type in
        # the database.
        return 'CharField'

    def to_python(self, value):
        if isinstance(value, basestring):
            # De-Serialize into timedelta.
            return pickle.loads(str(value))
        return value

    def get_prep_value(self, value):
        # Serialize the object.
        return pickle.dumps(value)

class MyModel(models.Model):
    """Dummy implementation of a model.
    """
    timedelta = TimeDeltaField(default=datetime.timedelta(days=30))

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

This entitles us to use APIs such as:

# Creates a models instance with default value of timedelta.
MyModel.objects.create()

# Creates an instance with your own specified timedelta value.
MyModel.objects.create( \
    timedelta=datetime.timedelta(datetime.timedelta(days=10, seconds=100))
)

This code has been written and tested in Django 1.4 pre-alpha version.