Я столкнулся с этой проблемой, когда попытался сохранить модель 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, просто добавьте код для обработки типа unserializable-to-JSON (например, Enum
or 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 (Django и т. Д.) В целом
- Кроме того, если вы поняли, как
json.dumps
работает, это решение также работает с Python (без ORM) в целом тоже
Любые вопросы, пожалуйста, оставляйте в разделе комментариев. Спасибо!