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.