Search code examples
pythonjsonobjectserializationtinydb

Serialize Python object in another object with json?


how can I serialize an object which has another object in his attributes using TinyDB ?

class address:
    def __init__(self, country, city):
        self.country = country
        self.city = city


class Person:
    def __init__(self, name, address):
        self.name = name
        self.address = address


add = Address("USA", "New York")
person = Person("John", add)

Now, when I try to serialize person I got this error:

TypeError: Object of type Address is not JSON serializable

I know that JSON can't serialize objects and I have to convert them to dicts before that. I can do it for a simple object like that:

from tinydb import TinyDB

db = TinyDB


serialized_address = {"country": self.country, "city": self.city}

db.insert(serialized_address)

But how am I supposed to do this when there is an instance in another instance ? (I'm forced to use TinyDB and JSON for my project...)

The only clue I have, is to put a reference of the first object instead of the object itself, in the second object arguments, but I can't figure out how to do that...


Solution

  • One option is to convert any existing classes into dataclasses, which are just normal classes with some autogenerated methods like __init__ and __repr__ for example.

    Then, you can recursively serialize a nested dataclass model using the asdict helper function that dataclasses provides:

    from dataclasses import dataclass, asdict
    
    
    @dataclass
    class Person:
        name: str
        address: 'Address'
    
    
    @dataclass
    class Address:
        country: str
        city: str
    
    
    add = Address("USA", "New York")
    person = Person("John", add)
    
    serialized = asdict(person)
    print(serialized)
    # {'name': 'John', 'address': {'country': 'USA', 'city': 'New York'}}
    

    If you need to work with more complex types like datetime, or else need to load or de-serialize json to a dataclass model, I would check out a de/serialization library like the dataclass-wizard, which can help further simplify this process:

    from dataclasses import dataclass
    from datetime import date
    
    from dataclass_wizard import fromdict, asdict
    
    
    @dataclass
    class Person:
        name: str
        address: 'Address'
        birth_date: date
    
    
    @dataclass
    class Address:
        country: str
        city: str
    
    
    person = fromdict(Person, {'name': 'John', 'BirthDate': '1990-01-01', 'address': {'country': 'USA', 'city': 'New York'}})
    
    print(person)
    # Person(name='John', address=Address(country='USA', city='New York'), birth_date=datetime.date(1990, 1, 1))
    
    serialized = asdict(person)
    print(serialized)
    # {'name': 'John', 'address': {'country': 'USA', 'city': 'New York'}, 'birthDate': '1990-01-01'}