-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
ValidateOnType
Mike Bayer edited this page Feb 20, 2014
·
2 revisions
SQLAlchemy normally defers to the DBAPI and database in use to validate that information being passed is as expected. To do so within the Python layer adds performance and complexity overhead, makes assumptions about the calling code, and in most cases is redundant versus what the database already does.
The recipe below shows how to link validation functions to the types of each column, when you do want up-front validation and possibly value coercion, as values are set. The attribute events system is used to intercept column-based attributes as they are instrumented, attaching a listener which can operate upon the value before it's assigned.
#!python
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import event
import datetime
Base= declarative_base()
def validate_int(value):
if isinstance(value, basestring):
value = int(value)
else:
assert isinstance(value, integer)
return value
def validate_string(value):
assert isinstance(value, basestring)
return value
def validate_datetime(value):
assert isinstance(value, datetime.datetime)
return value
validators = {
Integer:validate_int,
String:validate_string,
DateTime:validate_datetime,
}
@event.listens_for(Base, 'attribute_instrument')
def configure_listener(class_, key, inst):
if not hasattr(inst.property, 'columns'):
return
@event.listens_for(inst, "set", retval=True)
def set_(instance, value, oldvalue, initiator):
validator = validators.get(inst.property.columns[0].type.__class__)
if validator:
return validator(value)
else:
return value
class MyObject(Base):
__tablename__ = 'mytable'
id = Column(Integer, primary_key=True)
svalue = Column(String)
ivalue = Column(Integer)
dvalue = Column(DateTime)
m = MyObject()
m.svalue = "ASdf"
m.ivalue = "45"
m.dvalue = "not a date"