SQLAlchemy - 最大列长度

11

在SQLAlchemy中,是否可以强制执行分配给映射列的值的最大字符串长度?我想要的只是在赋值的字符串值长于类型为STRING的相应表列的长度时引发异常。

谢谢


请提供您用于定义表格和映射到类的代码。据我所知,数据库应该引发一个错误,通过SQLAlchemy传播回来。请发布代码以提供一些提示,以了解您现在正在尝试什么。 - S.Lott
@S.Lott MySQL在插入/更新时不会检查字符串长度。它会悄悄地截断太长的字符串。 - codeape
2个回答

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来使用此扩展。如果您希望它适用于所有派生自其的类,则还可以将其设置为基类。


1
是的,它解决了问题,但我有数十个这样的列,所以使用该属性并不是很方便。使用SQLAlchemy类型系统的解决方案会更好。 - honzas
我添加了一个可以用于SQLAlchemy特定验证器的示例。 - Ants Aasma

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

我不确定,在最初的问题时它是否存在,但现在使用validates()装饰器会更容易吧? - ubert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接