Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Work on a version of this field that uses python timedeltas internall…
…y to store interval
- Loading branch information
Showing
7 changed files
with
181 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,92 @@ | ||
# -*- coding: utf-8 -*- | ||
from datetime import timedelta | ||
from django.core import exceptions | ||
from django.db.models.fields import Field | ||
from django.db import models | ||
from django.utils.translation import ugettext_lazy as _ | ||
from django.utils.encoding import smart_str, smart_unicode | ||
|
||
from durationfield.utils.timestring import to_timedelta | ||
from durationfield.forms.fields import DurationField as FDurationField | ||
from django.db.models.fields import DecimalField | ||
|
||
class DurationField(DecimalField): | ||
class DurationField(Field): | ||
""" | ||
A duration field is used | ||
""" | ||
description = _("A duration of time") | ||
|
||
default_error_messages = { | ||
'invalid': _("This value must be in \"w d h min s ms us\" format."), | ||
'unknown_type': _("The value's type could not be converted"), | ||
} | ||
|
||
description = "A duration of time" | ||
__metaclass__ = models.SubfieldBase | ||
|
||
def __init__(self, *args, **kwargs): | ||
super(DurationField, self).__init__(*args, **kwargs) | ||
self.max_digits, self.decimal_places = 20, 6 | ||
#self.max_digits, self.decimal_places = 20, 6 | ||
|
||
def get_internal_type(self): | ||
return "IntegerField" | ||
return "DurationField" | ||
|
||
def db_type(self): | ||
# Django 1.1.X does not support multiple db's and therefore does not | ||
# call db_type passing in the connection string. | ||
""" | ||
Returns the database column data type for this field, for the provided connection. | ||
Django 1.1.X does not support multiple db's and therefore does not pass in the db | ||
connection string. Called by Django only when the framework constructs the table | ||
""" | ||
return "bigint" | ||
|
||
def get_db_prep_save(self, value): | ||
def get_db_prep_value(self, value): | ||
""" | ||
Returns field's value prepared for interacting with the database backend. In our case this is | ||
an integer representing the number of microseconds elapsed. | ||
""" | ||
if value is None: | ||
return None # db NULL | ||
if isinstance(value, int) or isinstance(value, long): | ||
value = timedelta(microseconds=value) | ||
return value.days * 24 * 3600 * 1000000 + value.seconds * 1000000 + value.microseconds | ||
|
||
def get_db_prep_save(self, value): | ||
return self.get_db_prep_value(value) | ||
|
||
def value_to_string(self, obj): | ||
value = self._get_val_from_obj(obj) | ||
return smart_unicode(from_timedelta(value)) | ||
|
||
def to_python(self, value): | ||
return value | ||
""" | ||
Converts the input value into the timedelta Python data type, raising | ||
django.core.exceptions.ValidationError if the data can't be converted. | ||
Returns the converted value as a timedelta. | ||
""" | ||
|
||
# Note that value may be coming from the database column or a serializer so we should | ||
# handle a timedelta, string or an integer | ||
if value is None: | ||
return value | ||
|
||
if isinstance(value, timedelta): | ||
return value | ||
|
||
if isinstance(value, int) or isinstance(value, long): | ||
return timedelta(microseconds=value) | ||
|
||
# Try to parse the value | ||
str = smart_str(value) | ||
if isinstance(str, basestring): | ||
try: | ||
return to_timedelta(value) | ||
except ValueError: | ||
raise exceptions.ValidationError(self.default_error_messages['invalid']) | ||
|
||
raise exceptions.ValidationError(self.default_error_messages['unknown_type']) | ||
|
||
def formfield(self, **kwargs): | ||
defaults = {'form_class': FDurationField} | ||
defaults.update(kwargs) | ||
return super(DurationField, self).formfield(**defaults) | ||
|
||
|
||
|
||
def formfield(self, form_class=FDurationField, **kwargs): | ||
return super(DurationField, self).formfield(form_class, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from fields import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,33 @@ | ||
from django.forms.fields import Field | ||
from django.core.exceptions import ValidationError | ||
from durationfield.utils.timestring import to_timedelta | ||
from django.forms import ValidationError | ||
from django.utils.translation import ugettext_lazy as _ | ||
from widgets import DurationInput | ||
|
||
from durationfield.forms.widgets import DurationInput | ||
from durationfield.utils.timestring import to_timedelta | ||
|
||
class DurationField(Field): | ||
widget = DurationInput | ||
|
||
default_error_messages = { | ||
'invalid': u'Enter a valid duration.', | ||
'max_value': _(u'Ensure this value is less than or equal to %(limit_value)s.'), | ||
'min_value': _(u'Ensure this value is greater than or equal to %(limit_value)s.'), | ||
'invalid': _('Enter a valid duration.'), | ||
} | ||
|
||
def __init__(self, min_value=None, max_value=None, *args, **kwargs): | ||
def __init__(self, *args, **kwargs): | ||
super(DurationField, self).__init__(*args, **kwargs) | ||
|
||
if max_value is not None: | ||
self.validators.append(validators.MaxValueValidator(max_value)) | ||
if min_value is not None: | ||
self.validators.append(validators.MinValueValidator(min_value)) | ||
|
||
def clean(self, value): | ||
""" | ||
Validates max_value and min_value. | ||
Returns a datetime.timedelta object. | ||
""" | ||
super(DurationField, self).clean(value) | ||
try: | ||
return to_timedelta(value) | ||
except ValueError, e: | ||
raise ValidationError(e) | ||
|
||
if self.max_value is not None and value > self.max_value: | ||
raise ValidationError(self.error_messages['max_value'] % {'max': self.max_value}) | ||
|
||
if self.min_value is not None and value < self.min_value: | ||
raise ValidationError(self.error_messages['min_value'] % {'min': self.min_value}) | ||
|
||
return value | ||
raise ValidationError(self.default_error_messages['invalid']) | ||
|
||
def to_python(self, value): | ||
try: | ||
return to_timedelta(value) | ||
except ValueError, e: | ||
raise ValidationError(e) | ||
raise ValidationError(self.default_error_messages['invalid']) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters