Я столкнулся с этой проблемой, когда попытался сохранить модель Peewee в PostgreSQL JSONField
.
Поработав некоторое время, вот общее решение.
Ключом к моему решению является просмотр исходного кода Python и понимание того, что в документации кода (описанной здесь ) уже объясняется, как расширить существующий json.dumps
для поддержки других типов данных.
Предположим, у вас есть модель, которая содержит некоторые поля, которые нельзя сериализовать в JSON, и модель, которая содержит поле JSON, изначально выглядит так:
class SomeClass(Model):
json_field = JSONField()
Просто определите пользовательский JSONEncoder
следующим образом:
class CustomJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
return < whatever value you want >
return json.JSONEncoder.default(self, obj)
@staticmethod
def json_dumper(obj):
return json.dumps(obj, cls=CustomJsonEncoder)
А затем просто используйте его в своем JSONField
, как показано ниже:
class SomeClass(Model):
json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)
Ключ - default(self, obj)
метод выше. Для каждой жалобы ... is not JSON serializable
, которую вы получаете от Python, просто добавьте код для обработки типа, не поддающегося обработке в JSON (например, Enum
или datetime
)
Например, вот как я поддерживаю класс, унаследованный от Enum
:
class TransactionType(Enum):
CURRENT = 1
STACKED = 2
def default(self, obj):
if isinstance(obj, TransactionType):
return obj.value
return json.JSONEncoder.default(self, obj)
Наконец, с помощью кода, реализованного, как указано выше, вы можете просто преобразовать любые модели Peewee в объект с поддержкой JSON, как показано ниже:
peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)
Хотя приведенный выше код был (несколько) специфичен для Peewee, но я думаю:
- Это применимо к другим ORM (Джанго и т. Д.) В целом
- Кроме того, если вы поняли, как работает
json.dumps
, это решение также работает с Python (без ORM) в целом
Любые вопросы, пожалуйста, оставляйте в разделе комментариев. Спасибо!