使用 List 参数调用经过棉花糖验证的 GET 端点

Call marshmallow validated GET endpoint with List parameter

我有一个像这样的棉花糖模式验证:

class MyFilterSchema(Schema):             
    ids = fields.List(fields.Str(validate=non_empty), required=True)

然后在我的端点调用模式验证:MyFilterSchema().load(flask.request.args) 现在我尝试调用使用此验证的 HTTP GET 端点。但是我得到 'ids': ['Not a valid list.'] 我尝试了不同的方法:

 /myendpoint?ids=1,2,3
 /myendpoint?ids=1&ids=2
 /myendpoint?ids=[1,2]

但运气不好。必须如何调用端点才能使 marshmallow 将我的 GET 参数识别为列表?

一种方法是使用验证字段的自定义实现而不是集成列表字段。

class DelimitedListField(fields.List):
    def _deserialize(self, value, attr, data, **kwargs):
        try:                                                    
            return value.split(",")                        
        except AttributeError:                                                                                                                                               
            raise exceptions.ValidationError(
                f"{attr} is not a delimited list it has a non string value {value}."
            )

这可以在如下模式中使用:

class MyFilterSchema(Schema):             
    ids = DelimitedListField(fields.Str(validate=non_empty), required=True)

并且会接受以下格式的呼叫:

/myendpoint?ids=1,2,3

要基于 Eisen 的答案,支持 Mashmallow 的所有验证和反序列化,您需要做更多的事情:

class DelimitedListField(fields.List):
    def __init__(self, cls_or_instance: typing.Union[fields.Field, type], **kwargs):
        super().__init__(cls_or_instance, **kwargs)

    def _deserialize(self, value, attr, data, **kwargs) -> typing.List[typing.Any]:
        try:
            logger.info(f"value={value}")
            list = value.split(",")
            logger.info(f"list={list}")
            return super()._deserialize(list, attr, data, **kwargs)
        except AttributeError:
            raise marshmallow.exceptions.ValidationError(
                f"{attr} is not a delimited list it has a non string value {value}."
            )