Python棉花糖字段可以是两种不同的类型

Python棉花糖字段可以是两种不同的类型,python,marshmallow,Python,Marshmallow,我想指定一个棉花糖模式。对于我的一个字段,我希望对其进行验证,但它可以是字符串或字符串列表。我尝试过原始字段类型,但是它允许所有内容通过。有没有办法只验证我想要的两种类型 大概 value = fields.Str() or fields.List() 今天我遇到了同样的问题,我提出了这个解决方案: class ValueField(fields.Field): def _deserialize(self, value, attr, data, **kwargs): i

我想指定一个棉花糖模式。对于我的一个字段,我希望对其进行验证,但它可以是字符串或字符串列表。我尝试过原始字段类型,但是它允许所有内容通过。有没有办法只验证我想要的两种类型

大概

value = fields.Str() or fields.List()

今天我遇到了同样的问题,我提出了这个解决方案:

class ValueField(fields.Field):
    def _deserialize(self, value, attr, data, **kwargs):
        if isinstance(value, str) or isinstance(value, list):
            return value
        else:
            raise ValidationError('Field should be str or list')


class Foo(Schema):
    value = ValueField()
    other_field = fields.Integer()
您可以创建一个自定义字段并重载
\u反序列化
方法,以便验证代码是否为所需类型的实例。 我希望它对你有用

foo.load({'value': 'asdf', 'other_field': 1})
>>> {'other_field': 1, 'value': 'asdf'}
foo.load({'value': ['asdf'], 'other_field': 1})
>>> {'other_field': 1, 'value': ['asdf']}
foo.load({'value': 1, 'other_field': 1})
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Users/webinterpret/Envs/gl-gs-onboarding-api/lib/python3.7/site-packages/marshmallow/schema.py", line 723, in load
    data, many=many, partial=partial, unknown=unknown, postprocess=True
  File "/Users/webinterpret/Envs/gl-gs-onboarding-api/lib/python3.7/site-packages/marshmallow/schema.py", line 904, in _do_load
    raise exc
marshmallow.exceptions.ValidationError: {'value': ['Field should be str or list']}
foo.load({'value':'asdf','other_field':1})
>>>{'other_field':1,'value':'asdf'}
load({'value':['asdf'],'other_field':1})
>>>{'other_field':1,'value':['asdf']}
load({'value':1,'other_field':1})
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/Users/webexploration/Envs/gl-gs-onboarding-api/lib/python3.7/site-packages/marshmallow/schema.py”,第723行,已加载
数据,多=多,部分=部分,未知=未知,后处理=真
文件“/Users/webexploration/Envs/gl-gs-onboarding-api/lib/python3.7/site-packages/marshmallow/schema.py”,第904行,加载
加薪
marshmallow.exceptions.ValidationError:{'value':['字段应为str或list']}
映射解决方案,类似于上述:

from typing import List, Mapping, Any
from marshmallow import Schema, fields
from marshmallow.exceptions import ValidationError


class UnionField(fields.Field):
    """Field that deserializes multi-type input data to app-level objects."""

    def __init__(self, val_types: List[fields.Field]):
        self.valid_types = val_types
        super().__init__()

    def _deserialize(
        self, value: Any, attr: str = None, data: Mapping[str, Any] = None, **kwargs
    ):
        """
        _deserialize defines a custom Marshmallow Schema Field that takes in mutli-type input data to
        app-level objects.
        
        Parameters
        ----------
        value : {Any}
            The value to be deserialized.
        
        Keyword Parameters
        ----------
        attr : {str} [Optional]
            The attribute/key in data to be deserialized. (default: {None})
        data : {Optional[Mapping[str, Any]]}
            The raw input data passed to the Schema.load. (default: {None})
        
        Raises
        ----------
        ValidationError : Exception
            Raised when the validation fails on a field or schema.
        """
        errors = []
        # iterate through the types being passed into UnionField via val_types
        for field in self.valid_types:
            try:
                # inherit deserialize method from Fields class
                return field.deserialize(value, attr, data, **kwargs)
            # if error, add error message to error list
            except ValidationError as error:
                errors.append(error.messages)
                raise ValidationError(errors)
使用:


信贷:Anna K

棉花糖oneofschema项目在这里有一个很好的解决方案

从他们的示例代码:

import marshmallow
import marshmallow.fields
from marshmallow_oneofschema import OneOfSchema


class Foo:
    def __init__(self, foo):
        self.foo = foo


class Bar:
    def __init__(self, bar):
        self.bar = bar


class FooSchema(marshmallow.Schema):
    foo = marshmallow.fields.String(required=True)

    @marshmallow.post_load
    def make_foo(self, data, **kwargs):
        return Foo(**data)


class BarSchema(marshmallow.Schema):
    bar = marshmallow.fields.Integer(required=True)

    @marshmallow.post_load
    def make_bar(self, data, **kwargs):
        return Bar(**data)


class MyUberSchema(OneOfSchema):
    type_schemas = {"foo": FooSchema, "bar": BarSchema}

    def get_obj_type(self, obj):
        if isinstance(obj, Foo):
            return "foo"
        elif isinstance(obj, Bar):
            return "bar"
        else:
            raise Exception("Unknown object type: {}".format(obj.__class__.__name__))


MyUberSchema().dump([Foo(foo="hello"), Bar(bar=123)], many=True)
# => [{'type': 'foo', 'foo': 'hello'}, {'type': 'bar', 'bar': 123}]

MyUberSchema().load(
    [{"type": "foo", "foo": "hello"}, {"type": "bar", "bar": 123}], many=True
)
# => [Foo('hello'), Bar(123)]

也许这将有助于更好的工作,如果我们有像“一个”领域的东西,我会很好。
import marshmallow
import marshmallow.fields
from marshmallow_oneofschema import OneOfSchema


class Foo:
    def __init__(self, foo):
        self.foo = foo


class Bar:
    def __init__(self, bar):
        self.bar = bar


class FooSchema(marshmallow.Schema):
    foo = marshmallow.fields.String(required=True)

    @marshmallow.post_load
    def make_foo(self, data, **kwargs):
        return Foo(**data)


class BarSchema(marshmallow.Schema):
    bar = marshmallow.fields.Integer(required=True)

    @marshmallow.post_load
    def make_bar(self, data, **kwargs):
        return Bar(**data)


class MyUberSchema(OneOfSchema):
    type_schemas = {"foo": FooSchema, "bar": BarSchema}

    def get_obj_type(self, obj):
        if isinstance(obj, Foo):
            return "foo"
        elif isinstance(obj, Bar):
            return "bar"
        else:
            raise Exception("Unknown object type: {}".format(obj.__class__.__name__))


MyUberSchema().dump([Foo(foo="hello"), Bar(bar=123)], many=True)
# => [{'type': 'foo', 'foo': 'hello'}, {'type': 'bar', 'bar': 123}]

MyUberSchema().load(
    [{"type": "foo", "foo": "hello"}, {"type": "bar", "bar": 123}], many=True
)
# => [Foo('hello'), Bar(123)]