Вопрос-Ответ

How can I overcome "datetime.datetime not JSON serializable"?

Как я могу преодолеть "datetime.datetime не сериализуется в JSON"?

У меня есть базовый dict следующим образом:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

Когда я пытаюсь сделать jsonify(sample) я получаю:


Ошибка типа: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) не сериализуется в JSON


Что я могу сделать, чтобы мой образец словаря мог преодолеть приведенную выше ошибку?

Примечание: Хотя это может быть и не актуально, словари генерируются в результате извлечения записей из mongodb где при распечатке str(sample['somedate']) выводится 2012-08-08 21:46:24.862000.

Переведено автоматически
Ответ 1

Мой быстрый и грязный дамп JSON, который съедает даты и все остальное:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)

default это функция, применяемая к объектам, которые не сериализуемы.

В данном случае это str, поэтому он просто преобразует все, чего он не знает, в строки. Который отлично подходит для сериализации, но не так хорош при десериализации (отсюда "быстрый и грязный"), поскольку что угодно могло быть преобразовано в строку без предупреждения, например функция или массив numpy.


Ответ 2

Основываясь на других ответах, простое решение, основанное на конкретном сериализаторе, который просто преобразует datetime.datetime и datetime.date объекты в строки.

from datetime import date, datetime

def json_serial(obj):
"""JSON serializer for objects not serializable by default json code"""

if isinstance(obj, (datetime, date)):
return obj.isoformat()
raise TypeError ("Type %s not serializable" % type(obj))

Как видно, код просто проверяет, относится ли объект к классу datetime.datetime или datetime.date, а затем использует .isoformat() для создания его сериализованной версии в соответствии с форматом ISO 8601, ГГГГ-ММ-DDTHH: MM: SS (который легко декодируется JavaScript). Если требуются более сложные сериализованные представления, вместо str () можно использовать другой код (примеры смотрите в других ответах на этот вопрос). Код заканчивается созданием исключения, чтобы разобраться со случаем, когда оно вызывается с несериализуемым типом.

Эту функцию json_serial можно использовать следующим образом:

from datetime import datetime
from json import dumps

print dumps(datetime.now(), default=json_serial)

Подробности о том, как работает параметр по умолчанию для json.dumps , можно найти в разделе "Основное использование документации модуля json ".

Ответ 3

Обновлено в 2018 году

Первоначальный ответ соответствовал способу представления полей "даты" в MongoDB в виде:

{"$date": 1506816000000}

Если вам нужно универсальное решение на Python для сериализации datetime в json, ознакомьтесь с ответом @jjmontes для быстрого решения, не требующего зависимостей.


Поскольку вы используете mongoengine (согласно комментариям), а pymongo является зависимостью, в pymongo есть встроенные утилиты, помогающие с сериализацией в json:

http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

Пример использования (сериализация):

from bson import json_util
import json

json.dumps(anObject, default=json_util.default)

Пример использования (десериализация):

json.loads(aJsonString, object_hook=json_util.object_hook)

Django

Django предоставляет собственный DjangoJSONEncoder сериализатор, который должным образом справляется с подобными задачами.

Видеть https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder

from django.core.serializers.json import DjangoJSONEncoder

return json.dumps(
item,
sort_keys=True,
indent=1,
cls=DjangoJSONEncoder
)

Одно различие, которое я заметил между DjangoJSONEncoder и использованием пользовательского default типа этого:

import datetime
import json

def default(o):
if isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat()

return json.dumps(
item,
sort_keys=True,
indent=1,
default=default
)

Заключается в том, что Django удаляет часть данных:

 "last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder 
"last_login": "2018-08-03T10:51:42.990239", # default

Итак, в некоторых случаях вам, возможно, придется быть осторожным с этим.

Ответ 4

Я только что столкнулся с этой проблемой, и мое решение заключается в создании подкласса json.JSONEncoder:

from datetime import datetime
import json

class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()

return json.JSONEncoder.default(self, o)

В вашем вызове сделайте что-то вроде: json.dumps(yourobj, cls=DateTimeEncoder) То.isoformat(), что я получил из одного из ответов выше.

2023-04-23 02:11 python json