class Float(Numeric):
def __init__(self, precision=10)
+ # DateTime, Date, and Time work with Python datetime objects
class DateTime(TypeEngine)
class Date(TypeEngine)
# as bind params, raw bytes to unicode as
# rowset values, using the unicode encoding
# setting on the engine (defaults to 'utf-8')
- class Unicode(String)
+ class Unicode(TypeDecorator)
# uses the pickle protocol to serialize data
# in/out of Binary columns
- class PickleType(Binary)
+ class PickleType(TypeDecorator)
More specific subclasses of these types are available, which various database engines may choose to implement specifically, allowing finer grained control over types:
### Creating your Own Types {@name=custom}
-User-defined types can be created, to support either database-specific types, or customized pre-processing of query parameters as well as post-processing of result set data. You can make your own classes to perform these operations. They are specified by subclassing the desired type class:
+User-defined types can be created, to support either database-specific types, or customized pre-processing of query parameters as well as post-processing of result set data. You can make your own classes to perform these operations. To augment the behavior of a `TypeEngine` type, such as `String`, the `TypeDecorator` class is used:
{python title="Basic Example"}
import sqlalchemy.types as types
- class MyType(types.String):
+ class MyType(types.TypeDecorator):
"""basic type that decorates String, prefixes values with "PREFIX:" on
the way in and strips it off on the way out."""
+ impl = types.String
def convert_bind_param(self, value, engine):
return "PREFIX:" + value
def convert_result_value(self, value, engine):
return value[7:]
+
+The `Unicode` and `PickleType` classes are instances of `TypeDecorator` already and can be subclassed directly.
-A common desire is for a "pickle" type, which overrides a Binary object to provide pickling behavior:
-
- {python title="Pickle Type"}
- import cPickle
-
- class PickleType(Binary):
- def __init__(self, protocol=pickle.HIGHEST_PROTOCOL):
- """allows the pickle protocol to be specified"""
- self.protocol = protocol
- def convert_result_value(self, value, engine):
- if value is None:
- return None
- buf = Binary.convert_result_value(self, value, engine)
- return pickle.loads(str(buf))
- def convert_bind_param(self, value, engine):
- if value is None:
- return None
- return Binary.convert_bind_param(self, pickle.dumps(value, self.protocol), engine)
- def get_constructor_args(self):
- return {}
-
-Which can be used like:
-
- {python}
- mytable = Table('mytable', engine,
- Column('id', Integer, primary_key=True),
- Column('data', PickleType()))
-
- my_object = MyObject()
- mytable.insert().execute(data=my_object)
-
-Another example, which illustrates a fully defined datatype. This just overrides the base type class TypeEngine:
+To build a type object from scratch, which will not have a corresponding database-specific implementation, subclass `TypeEngine`:
{python}
import sqlalchemy.types as types
return value
def convert_result_value(self, value, engine):
return value
- def adapt_args(self):
- """allows for the adaptation of this TypeEngine object into a new kind of type depending on its arguments."""
- return self
self._options[optkey] = mapper
return mapper
+ def _get_criterion(self, key, value):
+ """used by select_by to match a key/value pair against
+ local properties, column names, or a matching property in this mapper's
+ list of relations."""
+ if self.props.has_key(key):
+ return self.props[key].columns[0] == value
+ elif self.table.c.has_key(key):
+ return self.table.c[key] == value
+ else:
+ for prop in self.props.values():
+ c = prop.get_criterion(key, value)
+ if c is not None:
+ return c
+ else:
+ return None
+
def __getattr__(self, key):
if (key.startswith('select_by_') or key.startswith('get_by_')):
return getattr(self.query, key)
for key, value in params.iteritems():
if value is False:
continue
- c = self._get_criterion(key, value)
+ c = self.mapper._get_criterion(key, value)
if c is None:
raise InvalidRequestError("Cant find criterion for property '"+ key + "'")
if clause is None:
value.setup(key, statement, **kwargs)
return statement
- def _get_criterion(self, key, value):
- """used by select_by to match a key/value pair against
- local properties, column names, or a matching property in this mapper's
- list of relations."""
- if self.props.has_key(key):
- return self.props[key].columns[0] == value
- elif self.table.c.has_key(key):
- return self.table.c[key] == value
- else:
- for prop in self.props.values():
- c = prop.get_criterion(key, value)
- if c is not None:
- return c
- else:
- return None
def convert_result_value(self, value, engine):
return self.impl.convert_result_value(value, engine)
def copy(self):
- raise NotImplementedError()
+ instance = self.__class__.__new__(self.__class__)
+ instance.__dict__.update(self.__dict__)
+ return instance
def to_instance(typeobj):
if typeobj is None:
return value.decode(engine.encoding)
else:
return value
- def copy(self):
- return Unicode(self.impl.length)
class Integer(TypeEngine):
"""integer datatype"""
if value is None:
return None
return self.impl.convert_bind_param(pickle.dumps(value, self.protocol), engine)
- def copy(self):
- return PickleType(self.protocol)
class Boolean(TypeEngine):
pass