使用SQLAlchemy ORM,我希望确保值的列类型正确。
例如,假设我有一个Integer列。我尝试插入值“hello”,它不是一个有效的整数。SQLAlchemy将允许我这样做。直到后来,当我执行session.commit()
时,它才会引发异常:sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"…
。
我正在添加成批的记录,出于性能原因,我不想在每个add(…)
之后都提交。
那么我该如何:
只要我这样做,
发布于 2012-01-24 09:22:05
SQLAlchemy没有内置这一点,因为它将DBAPI/数据库作为验证和强制值的最佳和最有效的来源。
要构建自己的验证,通常使用TypeDecorator或ORM级别的验证。TypeDecorator的优点是它在核心上运行,并且可以相当透明,尽管它只在实际发出SQL时发生。
为了更快地进行验证和强制,这是在ORM级别。
在ORM层,可以通过@validates
进行临时验证
http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators
@validates use的事件系统也可以直接使用。您可以编写一个通用的解决方案,将您选择的验证器链接到要映射的类型:
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, int)
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,
}
# this event is called whenever an attribute
# on a class is instrumented
@event.listens_for(Base, 'attribute_instrument')
def configure_listener(class_, key, inst):
if not hasattr(inst.property, 'columns'):
return
# this event is called whenever a "set"
# occurs on that instrumented attribute
@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"
也可以使用TypeDecorator在类型级别构建验证和强制,尽管这只在发出SQL时才会发生,例如将utf-8字符串强制为unicode的示例:
http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode
发布于 2018-11-22 20:41:17
改进@zzzeek的答案,我建议以下解决方案:
from sqlalchemy import String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.event import listen_for
Base = declarative_base()
@listens_for(Base, 'attribute_instrument')
def configure_listener(table_cls, attr, col_inst):
if not hasattr(col_inst.property, 'columns'):
return
validator = getattr(col_inst.property.columns[0].type, 'validator', None)
if validator:
# Only decorate columns, that need to be decorated
@listens_for(col_inst, "set", retval=True)
def set_(instance, value, oldvalue, initiator):
return validator(value)
它可以让你做一些事情,比如:
class Name(String):
def validator(self, name):
if isinstance(name, str):
return name.upper()
raise TypeError("name must be a string")
这有两个好处:首先,只触发一个事件,而实际上有一个验证器附加到数据字段对象。它不会在没有定义验证函数的对象的set
事件上浪费宝贵的CPU周期。其次,它允许您定义自己的字段类型,只需在其中添加一个验证器方法,因此并不是所有要存储为Integer
等的内容都会经过相同的检查,只有从新字段类型派生出来的内容才会经过相同的检查。
https://stackoverflow.com/questions/8980735
复制相似问题