Я столкнулся с этой проблемой, когда попытался сохранить модель 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
или 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-seriazable, как показано ниже:
peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)
Хотя приведенный выше код был (несколько) специфичен для Peewee, но я думаю:
json.dumps
, это решение также работает с Python (без ORM) вообще . Все вопросы, пожалуйста, публикуйте в разделе комментариев. Спасибо!
Для reference— будущее возможности Python:
Запуск с Python 2.6 можно выразить двоичные литералы с помощью префикса 0b или 0B:
>>> 0b101111
47
можно также использовать новое мусорное ведро функция для получения двоичного представления числа:
>>> bin(173)
'0b10101101'
версия Разработки документации: Новые функции и возможности в Python 2.6
>>> print int('01010101111',2)
687
>>> print int('11111111',2)
255
Иначе.
Насколько я могу сказать, что Python, до 2,5, только поддерживает шестнадцатеричный & восьмеричные литералы. Я действительно находил некоторые дискуссии о добавлении двоичного файла к будущим версиям, но ничему определенному.
Я вполне уверен, это - одна из вещей, должных измениться в Python 3.0 с, возможно, мусорным ведром () для движения с шестнадцатеричным числом () и октябрь ().
РЕДАКТИРОВАНИЕ: ответ lbrandy корректен во всех случаях.