使用SQLAlChemy ORM,我希望确保值是其列的正确类型.

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

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

那么我该如何:

  • 我一做session.add(…)就提出异常
  • 或者,确保我插入的值可以转换为目标列数据类型,before将其添加到批处理中?
  • 或者任何其他方法来防止一个坏记录毁掉整个commit()个.

推荐答案

SQLAlChemy没有内置这一点,因为它将DBAPI/数据库作为最好、最有效的值验证和强制源.

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

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

验证可以是临时的,在ORM层,通过@validates:

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

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

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

Database相关问答推荐

什么时候需要手动重新分析 PostgreSQL 中的表?

MySQL FIND_IN_SET 的对面

SQL 查询至少其中一项

Android:我可以对多个数据库文件使用一个 SQLiteOpenHelper 类吗?

Laravel 5 从 URL 获取 ID

Spring 的 JdbcTemplate 是否在查询超时后关闭连接?

使用 PHPUnit 进行数据库测试的最佳实践

设置默认数据库连接 Rails

应用程序用户应该是数据库用户吗?

此平台不支持 LocalDB

获取错误函数 to_date(timestamp without time zone, unknown) 不存在

MongoDB 和 PostgreSQL 的思考

什么是数据库中的死锁?

如何在 Windows 中将用户添加到 PostgreSQL?

TransactionScope 是如何工作的?

CouchDB、MongoDB 和 Redis 中的哪个数据库适合从 Node.js 开始?

如何在文件系统中存储图像

Android - ViewHolder 模式是否在 CursorAdapter 中自动实现?

如何将纬度/经度对转换为 PostGIS 地理类型?

如何将空值传递给外键字段?