有没有 Python 实现的 .NET AutoMapper?

14

Automapper是一个对象映射器,我们可以在asp.net mvc中使用它将领域模型投影到视图模型中。

http://automapper.codeplex.com/

Python中是否有类似的实现供Django(模板)/Pylons使用?或者在Python世界中是否有这样的必要性?


你应该接受godswearhats的答案—— Django/Pylons 没有对象-对象映射功能,在大多数 Python 情况下通常也不需要,主要是因为 Python 是动态类型的语言,并且允许你使用其他方式来完成对象-对象映射所设计的大部分功能。 - Fabian Fagerholm
@Fabian/@godswearhats - 缓存对象到外部服务怎么样?Python中的大多数库使用内置的pickle库,该库在处理对象和嵌套对象图方面存在问题,因此这可能是需要自动映射器的用例。 - longda
4个回答

14

有的,确实有。

ObjectMapper是一个用于自动对象映射的类。它可以帮助你在项目层之间(数据层、服务层、视图层)以一种简单透明的方式创建对象。

https://pypi.python.org/pypi/object-mapper


GitHub 上只有 73 个星 :( - Neil

2
通常在Python中这不是必需的。我们有一些相当复杂的领域模型,可以轻松地在视图中使用它们,而不会注意到任何性能问题,我们每月提供数百万个页面浏览量。
此外,请记住,在Django中,“视图”等同于MVC中的“控制器”,而Django中的“模板”是MVC中的“视图”。因此,MTV而不是MVC。这最初让我感到困惑 :-)
如果您遇到了某些具体问题,请将其发布为问题...

12
使用这样的工具不仅是为了提高性能,更重要的是有助于实现基于层次结构的架构。即使在使用Python时这种架构并不常见,但仍然是一个不错的想法。 - Toilal
2
没错,@Toilal。这就是为什么我们有了Marshmallow。我很惊讶没有人提到它。 - code4life
使用Automapper的想法,正如@toilal所说,不是关于性能,而是关于架构层和解耦。 - Ernesto Gutierrez

0

最终我自己开发了一个基本版本的Automapper,模仿了.NET版本。

from typing import Protocol, TypeVar, Callable

from dataclasses import is_dataclass, fields
from dataclasses import MISSING

S = TypeVar("S")
T = TypeVar("T")


class IProfile(Protocol):

    mappings: dict[tuple[type[S], type[T]], dict[str, Callable[[S], object]]]

    def create_map(self,
                source_type: type[S],
                target_type: type[T],
                **mappings: Callable[[S], object]) -> None:
        ...


class IMapper(Protocol):

    def map(self, data: object, data_type: type[T]) -> T:
        ...


class Profile:

    mappings: dict[tuple[type[S], type[T]], dict[str, Callable[[S], object]]]

    def __init__(self) -> None:

        self.mappings = {}

    def create_map(self,
                source_type: type[S],
                target_type: type[T],
                **mappings: Callable[[S], object]) -> None:

        self.mappings[(source_type, target_type)] = dict(mappings)


class Mapper:

    _mappings: dict[tuple[type[S], type[T]], dict[str, Callable[[S], object]]]

    def __init__(self, profiles: list[IProfile]) -> None:

        self._mappings = {}

        for profile in profiles:
            for key, value in profile.mappings.items():
                self._mappings[key] = value

    def map(self, data: object, data_type: type[T]) -> T:

        if not is_dataclass(data_type):
            raise TypeError("type must be a dataclass")

        mapping_key = (type(data), data_type,)

        data_fields = fields(data_type)
        data_params = {}

        mappings = self._mappings.get(mapping_key, {})

        for field in data_fields:

            field_name, field_type = field.name, field.type
            field_value = getattr(data, field_name, None)

            if is_dataclass(field_type):
                field_value = self.map(field_value, field_type)
            else:
                if field_name in mappings:
                    field_value = mappings[field_name](field_value)

                if not field_value and field.default is not MISSING:
                    field_value = field.default

            data_params[field_name] = field_value

        return data_type(**data_params)

我不会声称它是完美的,但对于我所需的功能而言,它足够好用。

https://gist.github.com/ahancock1/5e5e0c665c3e696f1e8085f7b38bd123


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接