如何验证SQLAlchemy ORM中的列数据类型?

Nat*_*ate 20 python database orm sqlalchemy

使用SQLAlchemy ORM,我想确保值是其列的正确类型.

例如,假设我有一个Integer列.我尝试插入值"hello",这不是一个有效的整数.SQLAlchemy允许我这样做.只有在我执行时session.commit(),才会引发异常:sqlalchemy.exc.DataError: (DataError) invalid input syntax integer: "hello"….

我正在添加批量记录add(…),出于性能原因,我不想在每一个记录之后提交.

那么我怎么能:

  • 我尽快提出例外 session.add(…)
  • 或者,将其添加到批处理之前,确保我插入的值可以转换为目标Column数据类型?
  • 或任何其他方式来防止一个坏记录破坏整个commit().

zzz*_*eek 34

SQLAlchemy不构建它,因为它将DBAPI /数据库作为最佳和最有效的验证和强制来源.

要构建自己的验证,通常使用TypeDecorator或ORM级验证.TypeDecorator的优势在于它在核心运行并且可以非常透明,但它只在实际发出SQL时才会发生.

为了更快地进行验证和强制,这是在ORM级别.

验证可以在ORM层通过@validates以下方式进行临时验证:

http://docs.sqlalchemy.org/en/latest/orm/mapped_attributes.html#simple-validators

@validates使用的事件系统也可以直接使用.您可以编写一个通用解决方案,将您选择的验证器链接到要映射的类型:

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"
Run Code Online (Sandbox Code Playgroud)

验证和强制也可以使用TypeDecorator在类型级别构建,但这仅在发出SQL时,例如将utf-8字符串强制转换为unicode的示例:

http://docs.sqlalchemy.org/en/latest/core/custom_types.html#coercing-encoded-strings-to-unicode