Source

django-timedelta-field / timedelta / fields.py

from django.db import models
from django.core.exceptions import ValidationError

from collections import defaultdict
import datetime
import six

from .helpers import parse
from .forms import TimedeltaFormField

# TODO: Figure out why django admin thinks fields of this type have changed every time an object is saved.

# Define the different column types that different databases can use.
COLUMN_TYPES = defaultdict(lambda:"char(20)")
COLUMN_TYPES["django.db.backends.postgresql_psycopg2"] = "interval"
COLUMN_TYPES["django.contrib.gis.db.backends.postgis"] = "interval"

class TimedeltaField(models.Field):
    """
    Store a datetime.timedelta as an INTERVAL in postgres, or a 
    CHAR(20) in other database backends.
    """
    __metaclass__ = models.SubfieldBase
    _south_introspects = True
    
    description = "A datetime.timedelta object"
    
    def __init__(self, *args, **kwargs):
        self._min_value = kwargs.pop('min_value', None)
        self._max_value = kwargs.pop('max_value', None)
        super(TimedeltaField, self).__init__(*args, **kwargs)
    
    def to_python(self, value):
        if (value is None) or isinstance(value, datetime.timedelta):
            return value
        if isinstance(value, int):
            return datetime.timedelta(seconds=value)
        if value == "":
            if self.null:
                return None
            else:
                return datetime.timedelta(0)
        return parse(value)
    
    def get_prep_value(self, value):
        if self.null and value == "":
            return None
        if (value is None) or isinstance(value, six.string_types):
            return value
        return str(value).replace(',', '')
        
    def get_db_prep_value(self, value, connection=None, prepared=None):
        return self.get_prep_value(value)
        
    def formfield(self, *args, **kwargs):
        defaults = {'form_class':TimedeltaFormField}
        defaults.update(kwargs)
        return super(TimedeltaField, self).formfield(*args, **defaults)
    
    def validate(self, value, model_instance):
        super(TimedeltaField, self).validate(value, model_instance)
        if self._min_value is not None:
            if self._min_value > value:
                raise ValidationError('Less than minimum allowed value')
        if self._max_value is not None:
            if self._max_value < value:
                raise ValidationError('More than maximum allowed value')
    
    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return unicode(value)
    
    def get_default(self):
        """
        Needed to rewrite this, as the parent class turns this value into a
        unicode string. That sux pretty deep.
        """
        if self.has_default():
            if callable(self.default):
                return self.default()
            return self.get_prep_value(self.default)
        if not self.empty_strings_allowed or (self.null):
            return None
        return ""
        
    def db_type(self, connection):
        return COLUMN_TYPES[connection.settings_dict['ENGINE']]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.