为了账号安全,请及时绑定邮箱和手机立即绑定

使用 SQLAlchemy TypeDecorator 时 Marshmallow 验证错误地失败

使用 SQLAlchemy TypeDecorator 时 Marshmallow 验证错误地失败

米脂 2022-12-27 15:42:26
我创建了一个基于SQLAlchemy 示例的 TypeDecorator ,它在 32 个字符的十六进制字符串和BINARY存储 UUID 的数据库列之间进行转换:from __future__ import absolute_importimport uuidfrom sqlalchemy import types, func#https://docs.sqlalchemy.org/en/13/core/custom_types.html#backend-agnostic-guid-typeclass HashColumn(types.TypeDecorator):    impl=types.BINARY    def process_bind_param(self, value, dialect):        if value is not None:            return uuid.UUID(hex=value).bytes    def process_result_value(self, value, dialect):        return uuid.UUID(bytes=value).hex    def copy(self, **kw):        return HashColumn(self.impl.length)模型:def get_uuid():    return uuid.uuid4().hexclass School(db.Model):    """        description: A School    """    __tablename__ = "schools"    id = db.Column('school_id', HashColumn(length=16), primary_key=True, default=get_uuid)    ...但是,我遇到的问题是我的棉花糖模式(从 SQLAlchemy 模型生成)没有将此列视为 32 个字符的字符串:架构:from marshmallow_sqlalchemy import SQLAlchemyAutoSchema...class SchoolSchema(SQLAlchemyAutoSchema):    class Meta:        model = School        include_relationships = True        load_instance = True        include_fk = True...在我的代码中:try:    new_object = SchoolSchema().load(data, session=db.session)except ValidationError as err:    print(err.messages)    print(err.valid_data)当使用完全有效的 UUID 运行此代码时a5fad20c691546ae8871390d980aae6d,marshmallow 会抛出验证错误并提供以下输出:{"id": ["Longer than maximum length 16."]}由于我想在使用过程中将 UUID 格式化为 32 个字符的十六进制字符串(或适用的 python UUID),并BINARY(16)在存储到数据库之前转换为正确的格式,因此我需要消除此验证错误,但我不确定如何做到这一点,因为更改 SQLAlchemy 模型上的长度参数将意味着将创建数据库表BINARY(32)而不是BINARY(16),将长度加倍。是否可以设置 SQLAlchemyTypeDecorator以便它在数据库中存储一种长度 ( BINARY(16)) 的类型,但向CHAR(32)Python 和/或 SQLAlchemy 提供不同的长度 ( ) 以便 marshmallow 可以正确地将长度验证为 32 个字符的字符串?
查看完整描述

1 回答

?
holdtom

TA贡献1805条经验 获得超10个赞

到目前为止,我找到了两种方法来解决这个问题:


调整 TypeDecorator 的类型,使其像CHAR列而不是二进制列一样工作,并用于load_dialect_impl更改呈现给数据库的类型,指定不同的长度作为参数


class HashColumn(types.TypeDecorator):

    impl=types.CHAR


    def load_dialect_impl(self, dialect):

        return dialect.type_descriptor(types.BINARY(16))


   ...

(课程的其余部分与问题中的内容基本相同)


此更改允许我将HashColumn(length=16)定义从我的 DB 模型更改为HashColumn(length=32),从而允许 marshmallow 正确解释长度。


或者,我可以更改我的 API PATCH/更新端点的实现以从数据库中获取和更新现有对象,而不是创建一个全新的对象并尝试合并它们的值。这完全删除了 Marshmallow 验证,因为 ID 不再用于创建新对象,但是,对我来说,这感觉像是一种太多的解决方法,并且意味着,因为没有使用 Marshmallow 验证,它也不会验证任何其他数据字段。


查看完整回答
反对 回复 2022-12-27
  • 1 回答
  • 0 关注
  • 66 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信