SQLAlchemy - 最大列长度

11 投票
2 回答
29232 浏览
提问于 2025-04-15 19:37

在SQLAlchemy中,是否可以限制映射列中赋值字符串的最大长度?我想要的就是如果赋值的字符串长度超过了对应表中STRING类型列的长度,就抛出一个异常。

谢谢

2 个回答

0

这里有一个更新的版本,适合较新版本的sqlalchemy事件系统:

class InstallValidatorListeners(InstrumentationManager):
    def post_configure_attribute(self, class_, key, inst):
        """Add validators for any attributes that can be validated."""
        prop = inst.prop
        # Only interested in simple columns, not relations
        if isinstance(prop, ColumnProperty) and len(prop.columns) == 1:
            col = prop.columns[0]
            if isinstance(col.type, String) and col.type.length:
                sqlalchemy.event.listen(
                    getattr(class_, key), 'set', LengthValidator(col.type.length), retval=True)


class ValidationError(Exception):
    pass


class LengthValidator(AttributeExtension):
    def __init__(self, max_length):
        self.max_length = max_length

    def __call__(self, state, value, oldvalue, initiator):
        if len(value) > self.max_length:
            raise ValidationError(
                "Length %d exceeds allowed %d" % (len(value), self.max_length))
        return value
12

最简单的方法就是给映射的列重新命名,并通过一个属性来代理它:

class Something(Base):
    ...
    _foo = Column('foo', String(123))

    @property
    def foo(self):
        return self._foo

    @foo.setter
    def foo(self, value):
        if len(value) > _foo.type.length:
            raise Exception("Value too long")
        self._foo = value 

你可以很容易地把属性的创建过程提取出来,甚至可以使用像formencode这样的通用验证框架。


如果你需要一个更针对SQLAlchemy的解决方案,并且不介意使用特定的接口,那么SQLAlchemy有一个扩展机制,可以捕捉属性上的事件。使用这个机制的验证器大概是这样的:

from sqlalchemy.orm.interfaces import AttributeExtension, InstrumentationManager
from sqlalchemy.orm import ColumnProperty

class InstallValidatorListeners(InstrumentationManager):
    def post_configure_attribute(self, class_, key, inst):
        """Add validators for any attributes that can be validated."""
        prop = inst.prop
        # Only interested in simple columns, not relations
        if isinstance(prop, ColumnProperty) and len(prop.columns) == 1:
            col = prop.columns[0]
            # if we have string column with a length, install a length validator
            if isinstance(col.type, String) and col.type.length:
                inst.impl.extensions.insert(0, LengthValidator(col.type.length))

class ValidationError(Exception):
    pass

class LengthValidator(AttributeExtension):
    def __init__(self, max_length):
        self.max_length = max_length

    def set(self, state, value, oldvalue, initiator):
        if len(value) > self.max_length:
            raise ValidationError("Length %d exceeds allowed %d" %
                                (len(value), self.max_length))
        return value

然后你可以通过在任何想要验证的类上设置__sa_instrumentation_manager__ = InstallValidatorListeners来使用这个扩展。如果你希望它适用于所有从这个基类派生的类,也可以直接在基类上设置。

撰写回答