Saltar al contenido

¿Cómo superar “datetime.datetime not JSON serializable”?

Solución:

Mi volcado JSON rápido y sucio que come dátiles y todo:

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

default es una función aplicada a objetos que no son serializables.
En este caso es str, por lo que convierte todo lo que no conoce en cadenas. Lo cual es genial para la serialización, pero no tanto cuando se deserializa (de ahí el “rápido y sucio”) ya que cualquier cosa podría haber sido encadenada sin previo aviso, por ejemplo, una función o una matriz numpy.

Sobre la base de otras respuestas, una solución simple basada en un serializador específico que simplemente convierte datetime.datetime y datetime.date objetos a cadenas.

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))

Como se ve, el código solo verifica si el objeto es de clase datetime.datetime o datetime.date, y luego usa .isoformat() para producir una versión serializada, de acuerdo con el formato ISO 8601, AAAA-MM-DDTHH: MM: SS (que se decodifica fácilmente con JavaScript). Si se buscan representaciones serializadas más complejas, se podría usar otro código en lugar de str () (consulte otras respuestas a esta pregunta para ver ejemplos). El código termina generando una excepción, para tratar el caso de que se llame con un tipo no serializable.

Esta función json_serial se puede utilizar de la siguiente manera:

from datetime import datetime
from json import dumps

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

Los detalles sobre cómo funciona el parámetro predeterminado de json.dumps se pueden encontrar en la Sección Uso básico de la documentación del módulo json.

Actualizado para 2018

La respuesta original acomodaba la forma en que los campos de “fecha” de MongoDB se representaban como:

{"$date": 1506816000000}

Si desea una solución Python genérica para serializar datetime a json, consulte la respuesta de @jjmontes para obtener una solución rápida que no requiera dependencias.


Como está usando mongoengine (por comentarios) y pymongo es una dependencia, pymongo tiene utilidades integradas para ayudar con la serialización json:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

Uso de ejemplo (serialización):

from bson import json_util
import json

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

Uso de ejemplo (deserialización):

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

Django

Django proporciona un nativo DjangoJSONEncoder serializador que se ocupa de este tipo de forma adecuada.

Ver 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
)

Una diferencia que he notado entre DjangoJSONEncoder y usando una costumbre default como esto:

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
)

Es que Django quita un poco de los datos:

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

Por lo tanto, es posible que deba tener cuidado con eso en algunos casos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *