1

I am not sure if this question has been asked before but I can't find related custom mapping. Usually it is a direct JSON to object 1:1 mapping.

So here is my sample example:

class Test():
    id: str
    name: str
    msg: str

data = [
    {
        "id": "12345",
        "client": "test",
        "msg": "random"
    }, {
        "id": "54321",
        "client": "test-2",
        "msg": "random-2"
    }
]

So on above I have a JSON, I wanted to directly convert it to object I have on the first class. Note the "client" from the JSON becomes name.

So the final output when I do load the object it would become.

data = [
    {
        "id": "12345",
        "name": "test",
        "msg": "random"
    }, {
        "id": "54321",
        "name": "test-2",
        "msg": "random-2"
    }
]
martineau
  • 119,623
  • 25
  • 170
  • 301
logger
  • 1,983
  • 5
  • 31
  • 57
  • Your class doesn't _do_ anything. Should it be a dataclass? And where do you think the mapping client -> name comes from? – jonrsharpe Jun 03 '21 at 17:59
  • 1
    sorry I am fairly new to python coming from java background. what I was trying to do was create an custom object and have json mapped to that custom class. – logger Jun 03 '21 at 18:01
  • It's not clear what you actually tried to implement that. Python will deserialize the JSON to a list of dicts, if you want something else you have to customise the process or convert it afterwards. – jonrsharpe Jun 03 '21 at 18:03
  • Is your json correct? Test has a "name" property but the json in data has "client" istead of "name" – daniboy000 Jun 03 '21 at 18:08
  • And note that if your class doesn't have any _behaviour_ you don't need to do this at all - Python isn't Java, you can often just stick with a dictionary. – jonrsharpe Jun 03 '21 at 18:19
  • Your final output is not a list of instances of the class, it's a list of dictionaries (similar to what you would might get by loading the JSON input into Python via `json.load()` except for the client to name change). – martineau Jun 03 '21 at 18:31

2 Answers2

3
class Test():
    def __init__(self, id, client, msg):
        self.id = id
        self.name = client
        self.msg = msg

data = [
    {
        "id": "12345",
        "client": "test",
        "msg": "random"
    }, {
        "id": "54321",
        "client": "test-2",
        "msg": "random-2"
    }
]

# unpack values from dict and pass in as arguments for Test.__init__()
objects = [Test(**item) for item in data] 
Rafael Setton
  • 352
  • 1
  • 8
  • 1
    I don't think it makes sense to encode that mapping client parameter -> name attribute in the initialiser, what about when you create instances that _aren't_ from that JSON? Typically you'd do this as a class method, e.g. `Test.from_dict(item)`. – jonrsharpe Jun 03 '21 at 18:05
  • The questions says that it should map from THIS JSON format. For other formats, it would need a different class. – Rafael Setton Jun 03 '21 at 18:07
  • 1
    If it was _only_ for that JSON why would it need to rename a property? And would you really write multiple implementations of the same class for different sources? That seems like a bit of a smell. – jonrsharpe Jun 03 '21 at 18:13
  • 1
    Here's a good example of a healthier pattern: https://stackoverflow.com/a/30114013/3001761 – jonrsharpe Jun 03 '21 at 18:16
1

You can use Pydantic as well to define your class like showed bellow:

from pydantic import BaseModel

class User(BaseModel):
    id: str
    name: str
    msg: str

    def __init__(self, id: str, client: str, msg: str) -> None:
        super().__init__(id=id, name=client, msg=msg)

users = [
    {
        'id': '12345',
        'client': 'test',
        'msg': 'random',
    },
    {
        'id': '54321',
        'client': 'test-2',
        'msg': 'random-2',
    }
]

objects = [User(**user) for user in users]

print(objects)
# Output
[
   User(id='12345', name='test', msg='random'),
   User(id='54321', name='test-2', msg='random-2')
]
daniboy000
  • 1,069
  • 2
  • 16
  • 26