2016-06-23 14:11:20 +03:00
|
|
|
import datetime
|
|
|
|
import pytz
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
|
|
class Field(object):
|
|
|
|
|
|
|
|
creation_counter = 0
|
|
|
|
class_default = 0
|
|
|
|
db_type = None
|
|
|
|
|
|
|
|
def __init__(self, default=None):
|
|
|
|
self.creation_counter = Field.creation_counter
|
|
|
|
Field.creation_counter += 1
|
|
|
|
self.default = default or self.class_default
|
|
|
|
|
|
|
|
def to_python(self, value):
|
2016-06-26 16:52:25 +03:00
|
|
|
'''
|
2016-06-23 14:11:20 +03:00
|
|
|
Converts the input value into the expected Python data type, raising ValueError if the
|
|
|
|
data can't be converted. Returns the converted value. Subclasses should override this.
|
2016-06-26 16:52:25 +03:00
|
|
|
'''
|
2016-06-23 14:11:20 +03:00
|
|
|
return value
|
|
|
|
|
2016-06-23 19:05:44 +03:00
|
|
|
def validate(self, value):
|
2016-06-26 16:52:25 +03:00
|
|
|
'''
|
|
|
|
Called after to_python to validate that the value is suitable for the field's database type.
|
|
|
|
Subclasses should override this.
|
|
|
|
'''
|
2016-06-23 19:05:44 +03:00
|
|
|
pass
|
|
|
|
|
|
|
|
def _range_check(self, value, min_value, max_value):
|
2016-06-26 16:52:25 +03:00
|
|
|
'''
|
|
|
|
Utility method to check that the given value is between min_value and max_value.
|
|
|
|
'''
|
2016-06-23 19:05:44 +03:00
|
|
|
if value < min_value or value > max_value:
|
|
|
|
raise ValueError('%s out of range - %s is not between %s and %s' % (self.__class__.__name__, value, min_value, max_value))
|
|
|
|
|
2016-06-23 14:11:20 +03:00
|
|
|
def get_db_prep_value(self, value):
|
2016-06-26 16:52:25 +03:00
|
|
|
'''
|
2016-06-23 14:11:20 +03:00
|
|
|
Returns the field's value prepared for interacting with the database.
|
2016-06-26 16:52:25 +03:00
|
|
|
'''
|
2016-06-23 14:11:20 +03:00
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
class StringField(Field):
|
|
|
|
|
|
|
|
class_default = ''
|
|
|
|
db_type = 'String'
|
|
|
|
|
|
|
|
def to_python(self, value):
|
|
|
|
if isinstance(value, unicode):
|
|
|
|
return value
|
|
|
|
if isinstance(value, str):
|
|
|
|
return value.decode('UTF-8')
|
2016-06-23 18:24:20 +03:00
|
|
|
raise ValueError('Invalid value for %s: %r' % (self.__class__.__name__, value))
|
2016-06-23 14:11:20 +03:00
|
|
|
|
|
|
|
def get_db_prep_value(self, value):
|
|
|
|
if isinstance(value, unicode):
|
|
|
|
return value.encode('UTF-8')
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
class DateField(Field):
|
|
|
|
|
2016-06-23 19:05:44 +03:00
|
|
|
min_value = datetime.date(1970, 1, 1)
|
|
|
|
max_value = datetime.date(2038, 1, 19)
|
|
|
|
class_default = min_value
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'Date'
|
|
|
|
|
|
|
|
def to_python(self, value):
|
|
|
|
if isinstance(value, datetime.date):
|
|
|
|
return value
|
|
|
|
if isinstance(value, int):
|
|
|
|
return DateField.class_default + datetime.timedelta(days=value)
|
|
|
|
if isinstance(value, basestring):
|
2016-06-30 16:12:02 +03:00
|
|
|
if value == '0000-00-00':
|
|
|
|
return DateField.min_value
|
2016-06-23 14:11:20 +03:00
|
|
|
return datetime.datetime.strptime(value, '%Y-%m-%d').date()
|
2016-06-23 19:05:44 +03:00
|
|
|
raise ValueError('Invalid value for %s - %r' % (self.__class__.__name__, value))
|
|
|
|
|
|
|
|
def validate(self, value):
|
|
|
|
self._range_check(value, DateField.min_value, DateField.max_value)
|
2016-06-23 14:11:20 +03:00
|
|
|
|
|
|
|
def get_db_prep_value(self, value):
|
|
|
|
return value.isoformat()
|
|
|
|
|
|
|
|
|
|
|
|
class DateTimeField(Field):
|
|
|
|
|
|
|
|
class_default = datetime.datetime.fromtimestamp(0, pytz.utc)
|
|
|
|
db_type = 'DateTime'
|
|
|
|
|
|
|
|
def to_python(self, value):
|
|
|
|
if isinstance(value, datetime.datetime):
|
|
|
|
return value
|
|
|
|
if isinstance(value, datetime.date):
|
|
|
|
return datetime.datetime(value.year, value.month, value.day)
|
|
|
|
if isinstance(value, int):
|
|
|
|
return datetime.datetime.fromtimestamp(value, pytz.utc)
|
|
|
|
if isinstance(value, basestring):
|
2016-06-30 12:11:47 +03:00
|
|
|
return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
|
2016-06-23 19:05:44 +03:00
|
|
|
raise ValueError('Invalid value for %s - %r' % (self.__class__.__name__, value))
|
2016-06-23 14:11:20 +03:00
|
|
|
|
|
|
|
def get_db_prep_value(self, value):
|
|
|
|
return int(time.mktime(value.timetuple()))
|
|
|
|
|
|
|
|
|
|
|
|
class BaseIntField(Field):
|
|
|
|
|
|
|
|
def to_python(self, value):
|
2016-06-30 16:17:53 +03:00
|
|
|
try:
|
2016-06-23 14:11:20 +03:00
|
|
|
return int(value)
|
2016-06-30 16:17:53 +03:00
|
|
|
except:
|
|
|
|
raise ValueError('Invalid value for %s - %r' % (self.__class__.__name__, value))
|
2016-06-23 19:05:44 +03:00
|
|
|
|
|
|
|
def validate(self, value):
|
|
|
|
self._range_check(value, self.min_value, self.max_value)
|
2016-06-23 14:11:20 +03:00
|
|
|
|
|
|
|
|
|
|
|
class UInt8Field(BaseIntField):
|
|
|
|
|
2016-06-23 19:05:44 +03:00
|
|
|
min_value = 0
|
|
|
|
max_value = 2**8 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'UInt8'
|
|
|
|
|
|
|
|
|
|
|
|
class UInt16Field(BaseIntField):
|
|
|
|
|
2016-06-23 19:05:44 +03:00
|
|
|
min_value = 0
|
|
|
|
max_value = 2**16 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'UInt16'
|
|
|
|
|
|
|
|
|
|
|
|
class UInt32Field(BaseIntField):
|
|
|
|
|
2016-06-23 19:05:44 +03:00
|
|
|
min_value = 0
|
|
|
|
max_value = 2**32 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'UInt32'
|
|
|
|
|
|
|
|
|
|
|
|
class UInt64Field(BaseIntField):
|
|
|
|
|
2016-06-23 19:05:44 +03:00
|
|
|
min_value = 0
|
|
|
|
max_value = 2**64 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'UInt64'
|
|
|
|
|
|
|
|
|
|
|
|
class Int8Field(BaseIntField):
|
|
|
|
|
2016-06-23 19:05:44 +03:00
|
|
|
min_value = -2**7
|
|
|
|
max_value = 2**7 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'Int8'
|
|
|
|
|
|
|
|
|
|
|
|
class Int16Field(BaseIntField):
|
|
|
|
|
2016-06-26 17:41:17 +03:00
|
|
|
min_value = -2**15
|
|
|
|
max_value = 2**15 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'Int16'
|
|
|
|
|
|
|
|
|
|
|
|
class Int32Field(BaseIntField):
|
|
|
|
|
2016-06-26 17:41:17 +03:00
|
|
|
min_value = -2**31
|
|
|
|
max_value = 2**31 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'Int32'
|
|
|
|
|
|
|
|
|
|
|
|
class Int64Field(BaseIntField):
|
|
|
|
|
2016-06-26 17:41:17 +03:00
|
|
|
min_value = -2**63
|
|
|
|
max_value = 2**63 - 1
|
2016-06-23 14:11:20 +03:00
|
|
|
db_type = 'Int64'
|
|
|
|
|
|
|
|
|
|
|
|
class BaseFloatField(Field):
|
|
|
|
|
|
|
|
def to_python(self, value):
|
2016-06-30 16:17:53 +03:00
|
|
|
try:
|
2016-06-23 14:11:20 +03:00
|
|
|
return float(value)
|
2016-06-30 16:17:53 +03:00
|
|
|
except:
|
|
|
|
raise ValueError('Invalid value for %s - %r' % (self.__class__.__name__, value))
|
2016-06-23 14:11:20 +03:00
|
|
|
|
|
|
|
|
|
|
|
class Float32Field(BaseFloatField):
|
|
|
|
|
|
|
|
db_type = 'Float32'
|
|
|
|
|
|
|
|
|
|
|
|
class Float64Field(BaseFloatField):
|
|
|
|
|
|
|
|
db_type = 'Float64'
|
|
|
|
|