使用SQLAlchemy TypeDecorator的棉花糖验证错误地失败

问题描述 投票:0回答:1

我基于SQLAlchemy example创建了一个TypeDecorator,它在32个字符的十六进制字符串和存储UUID的BINARY数据库列之间进行转换:

from __future__ import absolute_import
import uuid
from sqlalchemy import types, func

#https://docs.sqlalchemy.org/en/13/core/custom_types.html#backend-agnostic-guid-type
class 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().hex

class School(db.Model):
    """
        description: A School
    """
    __tablename__ = "schools"
    id = db.Column('school_id', HashColumn(length=16), primary_key=True, default=get_uuid)
    ...

但是,我遇到的问题是,从SQLAlchemy模型生成的棉花糖模式没有将此列视为32个字符的字符串:

Schema:

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运行此代码时,棉花糖将引发验证错误并提供以下输出:

{"id": ["Longer than maximum length 16."]}

由于我想在使用过程中将UUID的格式设置为32个字符的十六进制字符串(或python UUID,如果适用),并在存储到数据库中之前将其转换为BINARY(16),因此我需要摆脱此验证错误,但是我不确定该怎么做,因为更改SQLAlchemy模型上的length参数将意味着将数据库表创建为BINARY(32)而不是BINARY(16),从而将长度加倍。

是否可以设置SQLAlchemy TypeDecorator,以便它在数据库中存储一种长度(BINARY(16))的类型,但与Python和/或SQLAlchemy呈现不同的长度(CHAR(32)),从而棉花糖可以正确验证长度为32个字符的字符串吗?

我已经在StackOverflow上寻找了类似这样的其他问题:

但是这似乎与转换类型本身有关,这已经在示例代码中完成了。我似乎找不到任何提及如何转换类型的[[length。

python validation sqlalchemy uuid marshmallow
1个回答
0
投票
到目前为止,我已经找到解决此问题的两种方法:

  1. 调整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)定义更改为HashColumn(length=32),从而使棉花糖可以正确解释长度。

  2. 或者,我可以更改API PATCH / update端点的实现,以从数据库中获取和更新现有对象,而不是创建一个全新的对象并尝试合并它们的值。由于不再使用ID来创建新对象,因此这完全删除了棉花糖验证,但是,对我来说,这感觉像是一种过度的解决方法,并且由于未使用棉花糖验证,因此它也不会验证任何其他数据字段。
© www.soinside.com 2019 - 2024. All rights reserved.