gpt4 book ai didi

python - 如何将 marshmallow-dataclass 与 marshmallow-oneofschema 结合起来用于多态结构?

转载 作者:行者123 更新时间:2023-12-05 01:36:22 29 4
gpt4 key购买 nike

我正在尝试将 marshmallow-dataclass 与 marshmallow-oneofschema 结合起来以处理提供给我并用于连接 java 和 python 应用程序的数据结构。

在 Java 中,这个概念通常被称为“鉴别器”,它由不同的框架实现:Jackson (de-)serialization for polymorph list

我认为这应该是可能的,但现在我面临以下问题:

Traceback (most recent call last):
File "one_file_dataclass_oneofschema_example.py", line 69, in <module>
ContainerSchema.load(example)
File "/site-packages/marshmallow_dataclass/__init__.py", line 473, in load
all_loaded = super().load(data, many=many, **kwargs)
File "/site-packages/marshmallow/schema.py", line 722, in load
return self._do_load(
File "/site-packages/marshmallow/schema.py", line 856, in _do_load
result = self._deserialize(
File "/site-packages/marshmallow/schema.py", line 664, in _deserialize
value = self._call_and_store(
File "/site-packages/marshmallow/schema.py", line 493, in _call_and_store
value = getter_func(data)
File "/site-packages/marshmallow/schema.py", line 661, in <lambda>
getter = lambda val: field_obj.deserialize(
File "/site-packages/marshmallow/fields.py", line 342, in deserialize
output = self._deserialize(value, attr, data, **kwargs)
File "/site-packages/marshmallow/fields.py", line 713, in _deserialize
result.append(self.inner.deserialize(each, **kwargs))
File "/site-packages/marshmallow/fields.py", line 342, in deserialize
output = self._deserialize(value, attr, data, **kwargs)
File "/site-packages/marshmallow/fields.py", line 597, in _deserialize
return self._load(value, data, partial=partial)
File "/site-packages/marshmallow/fields.py", line 580, in _load
valid_data = self.schema.load(value, unknown=self.unknown, partial=partial)
File "/site-packages/marshmallow_dataclass/__init__.py", line 481, in load
raise e
File "/site-packages/marshmallow_dataclass/__init__.py", line 479, in load
return clazz(**all_loaded)
TypeError: type object argument after ** must be a mapping, not SubClass1

在调试时,看起来已经反序列化的对象应该由 marshmallow_dataclass 再次反序列化。 :

def _base_schema(
clazz: type, base_schema: Optional[Type[marshmallow.Schema]] = None
) -> Type[marshmallow.Schema]:
"""
Base schema factory that creates a schema for `clazz` derived either from `base_schema`
or `BaseSchema`
"""

# Remove `type: ignore` when mypy handles dynamic base classes
# https://github.com/python/mypy/issues/2813
class BaseSchema(base_schema or marshmallow.Schema): # type: ignore
def load(self, data: Mapping, *, many: bool = None, **kwargs):
all_loaded = super().load(data, many=many, **kwargs)
many = self.many if many is None else bool(many)
if many:
return [clazz(**loaded) for loaded in all_loaded]
else:
return clazz(**all_loaded) # Here the error occurs.
return

我看过 this question 中提到的 post_load 逻辑,但不知道如何集成或是否有帮助。

这是我尝试过的:

from dataclasses import dataclass, field  # @UnusedImport
from typing import List

from marshmallow_dataclass import class_schema, add_schema
from marshmallow_oneofschema.one_of_schema import OneOfSchema


@dataclass
class BaseClass:
base_property_a: str


@dataclass
class SubClass1(BaseClass):
sub_property_1: str


@dataclass
class SubClass2(BaseClass):
sub_property_2: str


@dataclass
class Container:
container_property_c: str
some_objects: List[BaseClass]

# These schemas are required by OneOfSchema
SubClass1Schema = class_schema(SubClass1)()
SubClass2Schema = class_schema(SubClass2)()


class BaseClassSchema(OneOfSchema):
type_field = 'modelType'

type_schemas = {
'SubClass1': SubClass1Schema,
'SubClass2': SubClass2Schema
}

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

# Publishing BaseClassSchema so that it's use while not explicitly called.
add_schema(BaseClass, BaseClassSchema)

ContainerSchema = class_schema(Container)()


example = {
'container_property_c': 'bla',
'some_objects': [
{
'modelType': 'SubClass1',
'base_property_a': 'blub_a1',
'sub_property_1': 'blub_1'
},
{
'modelType': 'SubClass2',
'base_property_a': 'blub_a2',
'sub_property_2': 'blub_2'
}
]
}

ContainerSchema.load(example)

最佳答案

使用marshmallow-union找到了一个更简单的解决方案,这也是marshmallow-dataclass推荐的方式: https://github.com/lovasoa/marshmallow_dataclass/issues/62

from dataclasses import field  # @UnusedImport
from typing import List, Union

from marshmallow.validate import Equal
from marshmallow_dataclass import dataclass


@dataclass
class BaseClass:
base_property_a: str


@dataclass
class SubClass1(BaseClass):
modelType: str = field(metadata={"validate": Equal("SubClass1")})
sub_property_1: str


@dataclass
class SubClass2(BaseClass):
modelType: str = field(metadata={"validate": Equal("SubClass2")})
sub_property_2: str


@dataclass
class Container:
container_property_c: str
some_objects: List[Union[
SubClass1,
SubClass2
]]


example = {
'container_property_c': 'bla',
'some_objects': [
{
'modelType': 'SubClass1',
'base_property_a': 'blub_a1',
'sub_property_1': 'blub_1'
},
{
'modelType': 'SubClass2',
'base_property_a': 'blub_a2',
'sub_property_2': 'blub_2'
}
]
}

print(Container.Schema().load(example))

关于python - 如何将 marshmallow-dataclass 与 marshmallow-oneofschema 结合起来用于多态结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62183660/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com