[TIPS] Python Mixins - JsonSerializableMixin

By khoanc, at: March 1, 2025, 5:40 p.m.

Estimated Reading Time: __READING_TIME__ minutes

[TIPS] Python Mixins - JsonSerializableMixin
[TIPS] Python Mixins - JsonSerializableMixin

 

1. Basic JsonSerializableMixin

 

Quickly dumps all attributes into JSON

 

import json

class JsonSerializableMixin:
    def to_json(self):
        return json.dumps(vars(self))

class Product(JsonSerializableMixin):
    def __init__(self, name, price):
        self.name = name
        self.price = price

print(Product("Laptop", 1200).to_json())
# {"name": "Laptop", "price": 1200}

 

=> Fast and simple

 

BUT: Doesn’t handle nested objects or special types.

 

2. Custom Field Whitelist

 

Only include specific fields (__json_fields__)

 

import json

class JsonWhitelistMixin:
    __json_fields__ = []

    def to_json(self):
        data = {field: getattr(self, field) for field in self.__json_fields__ if hasattr(self, field)}
        return json.dumps(data)


class User(JsonWhitelistMixin):
    __json_fields__ = ["username", "email"]

    def __init__(self, username, email, password):
        self.username = username
        self.email = email
        self.password = password  # excluded


print(User("Joe", "[email protected]", "amazing Python team").to_json())
# {"username": "Joe", "email": "[email protected]"}

 

=> Great for security (hide passwords, tokens, etc.).

 

3. Nested Object Support

 

Handles lists, dicts, and other objects with to_json() or to_dict()

 

import json

class JsonNestedMixin:
    def to_dict(self):
        def convert(obj):
            if isinstance(obj, list):
                return [convert(i) for i in obj]
            if isinstance(obj, dict):
                return {k: convert(v) for k, v in obj.items()}
            if hasattr(obj, "to_dict"):
                return obj.to_dict()
            return obj

        return {k: convert(v) for k, v in vars(self).items()}

    def to_json(self):
        return json.dumps(self.to_dict())


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


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


p = Person("Glinteco", [Address("Hanoi", "Vietnam"), Address("Melbourne", "Australia")])
print(p.to_json())
# {"name": "Glinteco", "addresses": [{"city": "Hanoi", "country": "Vietnam"}, {"city": "Melbourne", "country": "Australia"}]}

 

=> Handles real-world object graphs.

 

4. Custom Encoder for Non-JSON Types

 

Supports datetime, Decimal, or other special types

 

import json, datetime, decimal


class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        if isinstance(obj, decimal.Decimal):
            return float(obj)
        return super().default(obj)


class JsonCustomEncoderMixin:
    def to_json(self):
        return json.dumps(vars(self), cls=CustomEncoder)


class Invoice(JsonCustomEncoderMixin):
    def __init__(self, amount, issued_at):
        self.amount = decimal.Decimal(amount)
        self.issued_at = issued_at


print(Invoice("1200.50", datetime.datetime(2025, 9, 6, 14, 30)).to_json())
# {"amount": 1200.5, "issued_at": "2025-09-06T14:30:00"}

 

=> Works with real-world data types that break vanilla json.dumps.

 

Tag list:

Subscribe

Subscribe to our newsletter and never miss out lastest news.