stoto
stoto

Reputation: 364

Is there a python implementation to .net automapper?

Automapper is a object-object mapper where we can use to project domain model to view model in asp.net mvc.

http://automapper.codeplex.com/

Is there equivalent implementation in Python for use in Django(Template)/Pylons ? Or is there necessity for this in Python world?

Upvotes: 14

Views: 7460

Answers (5)

SirPeace
SirPeace

Reputation: 109

The simplest way I could think of mapping objects in python is for them to have some kind of static adapt_... method. It looks like so:

class PostResponse:
    id: int
    title: str
    text: str
    created_at: str

    @classmethod
    def adapt_db(cls, db_post: Post) -> Self:
        model = cls(**{
            # basic mapping of identical fields
            **db_post.__dict__,

            # adjustments for concrete mismatches
            'created_at': str(db_post.created_at)
        })
        return model


db_post = find_post_in_db()
post_response = PostResponse.adapt_db(db_post)

Upvotes: 0

Adam H
Adam H

Reputation: 551

I ended up rolling my own basic version of automapper modelled on the .net version.

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)

I won't claim it's perfect but it works well enough for what I required.

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

Upvotes: 0

andnik
andnik

Reputation: 2804

Here is a nice Python automapper that is possible to extend for any framework models:

https://pypi.org/project/py-automapper/

Upvotes: 0

Frederico Cabral
Frederico Cabral

Reputation: 486

Yes, There is.

ObjectMapper is a class for automatic object mapping. It helps you to create objects between project layers (data layer, service layer, view) in a simple, transparent way.

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

Upvotes: 15

godswearhats
godswearhats

Reputation: 2255

This generally isn't necessary in Python. We have some pretty complex domain models and we're able to use them in our views easily, without noticing any performance issues, and we serve millions of page views a month.

Also remember that "view" in Django == "controller" in MVC, and "template" in Django is "view" in MVC. Hence MTV rather than MVC. Something that tripped me up initially :-)

If there's some specific issue you're running into, post that as a question too ...

Upvotes: 2

Related Questions