query leer dict create python json

leer - python json to dict



¿Cómo superar "datetime.datetime no JSON serializable"? (28)

Actualizado para 2018

La respuesta original se adaptó a 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 to json, consulte la respuesta de @jjmontes para obtener una solución rápida que no requiera dependencias.

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

Ejemplo de uso (serialización):

from bson import json_util import json json.dumps(anObject, default=json_util.default)

Ejemplo de uso (deserialización):

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

Django

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

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

He notado una diferencia entre DjangoJSONEncoder y el uso de un default personalizado como este:

def default(o): if type(o) is datetime.date or type(o) is datetime.datetime: return o.isoformat() return json.dumps( item, sort_keys=True, indent=1, default=default )

Es que Django elimina 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 tenga que tener cuidado con eso en algunos casos.

Tengo un dictado básico de la siguiente manera:

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

Cuando trato de hacer jsonify(sample) me sale:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable

¿Qué puedo hacer para que mi ejemplo de diccionario pueda superar el error anterior?

Nota: Aunque puede no ser relevante, los diccionarios se generan a partir de la recuperación de registros de mongodb, donde cuando imprimo str(sample[''somedate'']) , la salida es 2012-08-08 21:46:24.862000 .


Acabo de encontrar este problema y mi solución es la subclase 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)

En su llamada, haga algo como: json.dumps(yourobj, cls=DateTimeEncoder) El .isoformat() que obtuve de una de las respuestas anteriores.


Aquí está mi solución completa para convertir datetime a JSON y viceversa.

import calendar, datetime, json def outputJSON(obj): """Default JSON serializer.""" if isinstance(obj, datetime.datetime): if obj.utcoffset() is not None: obj = obj - obj.utcoffset() return obj.strftime(''%Y-%m-%d %H:%M:%S.%f'') return str(obj) def inputJSON(obj): newDic = {} for key in obj: try: if float(key) == int(float(key)): newKey = int(key) else: newKey = float(key) newDic[newKey] = obj[key] continue except ValueError: pass try: newDic[str(key)] = datetime.datetime.strptime(obj[key], ''%Y-%m-%d %H:%M:%S.%f'') continue except TypeError: pass newDic[str(key)] = obj[key] return newDic x = {''Date'': datetime.datetime.utcnow(), 34: 89.9, 12.3: 90, 45: 67, ''Extra'': 6} print x with open(''my_dict.json'', ''w'') as fp: json.dump(x, fp, default=outputJSON) with open(''my_dict.json'') as f: my_dict = json.load(f, object_hook=inputJSON) print my_dict

Salida

{''Date'': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, ''Extra'': 6} {''Date'': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, ''Extra'': 6}

Archivo JSON

{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}

Esto me ha permitido importar y exportar cadenas, ints, flotantes y objetos de fecha y hora. No debería ser difícil de extender para otros tipos.


Aquí está mi solución:

# -*- coding: utf-8 -*- import json class DatetimeEncoder(json.JSONEncoder): def default(self, obj): try: return super(DatetimeEncoder, obj).default(obj) except TypeError: return str(obj)

Entonces puedes usarlo así:

json.dumps(dictionnary, cls=DatetimeEncoder)


Aquí hay una solución simple para superar el problema "datetime no serializable por JSON".

enco = lambda obj: ( obj.isoformat() if isinstance(obj, datetime.datetime) or isinstance(obj, datetime.date) else None ) json.dumps({''date'': datetime.datetime.now()}, default=enco)

Salida: -> {"fecha": "2015-12-16T04: 48: 20.024609"}


Convertir la date en string

date = str(datetime.datetime(somedatetimehere))


Convertir la fecha en una cadena

sample[''somedate''] = str( datetime.utcnow() )


Debe utilizar el método .strftime() método .datetime.now() para hacerlo como un método serializable .

Aquí hay un ejemplo:

from datetime import datetime time_dict = {''time'': datetime.now().strftime(''%Y-%m-%dT%H:%M:%S'')} sample_dict = {''a'': 1, ''b'': 2} sample_dict.update(time_dict) sample_dict

Salida:

Out[0]: {''a'': 1, ''b'': 2, ''time'': ''2017-10-31T15:16:30''}


El método json.dumps puede aceptar un parámetro opcional llamado predeterminado que se espera sea una función. Cada vez que JSON intenta convertir un valor que no sabe cómo convertirlo, llamará a la función que le pasamos. La función recibirá el objeto en cuestión y se espera que devuelva la representación JSON del objeto.

from datetime import datetime


En general, hay varias formas de serializar fechas de datos, como:

  1. Cadena ISO, corta y puede incluir información de zona horaria, por ejemplo, la answer de @jgbarah
  2. Marca de tiempo (se pierden los datos de la zona horaria), por ejemplo, la answer de @JayTaylor
  3. Diccionario de propiedades (incluida la zona horaria).

Si está de acuerdo con la última forma, el paquete json_tricks maneja fechas, horas y tiempos de datos, incluidas las zonas horarias.

from datetime import datetime from json_tricks import dumps foo = {''title'': ''String'', ''datetime'': datetime(2012, 8, 8, 21, 46, 24, 862000)} dumps(foo)

lo que da:

{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}

Así que todo lo que necesitas hacer es

`pip install json_tricks`

y luego importar desde json_tricks lugar de json .

La ventaja de no almacenarlo como una sola cadena, int o float se produce cuando se decodifica: si encuentra solo una cadena o especialmente int o float, necesita saber algo sobre los datos para saber si es una fecha y hora. Como dict, puedes almacenar metadatos para que pueda decodificarse automáticamente, que es lo que json_tricks hace por ti. También es fácilmente editable para los humanos.

Descargo de responsabilidad: está hecho por mí. Porque tenía el mismo problema.


Esta Q se repite una y otra vez, una forma sencilla de parchear el módulo json de modo que la serialización sea compatible con datetime.

import json import datetime json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)

Utilice la serialización json como siempre lo hace, esta vez con la fecha y hora como serialización como isoformato.

json.dumps({''created'':datetime.datetime.now()})

Resultando en: ''{"created": "2015-08-26T14: 21: 31.853855"}''

Vea más detalles y algunas palabras de precaución en: : JSON datetime entre Python y JavaScript


La forma más sencilla de hacer esto es cambiar la parte del dict que está en formato de fecha y hora a isoformato. Ese valor será efectivamente una cadena en isoformato con la que json está de acuerdo.

v_dict = version.dict() v_dict[''created_at''] = v_dict[''created_at''].isoformat()


Me había encontrado con el mismo problema al externalizar el objeto del modelo django para volcarlo como JSON. Aquí es cómo puedes resolverlo.

def externalize(model_obj): keys = model_obj._meta.get_all_field_names() data = {} for key in keys: if key == ''date_time'': date_time_obj = getattr(model_obj, key) data[key] = date_time_obj.strftime("%A %d. %B %Y") else: data[key] = getattr(model_obj, key) return data


Mi solución (con menos verbosidad, creo):

def default(o): if type(o) is datetime.date or type(o) is datetime.datetime: return o.isoformat() def jsondumps(o): return json.dumps(o, default=default)

Luego use jsondumps lugar de json.dumps . Se imprimirá:

>>> jsondumps({''today'': datetime.date.today()}) ''{"today": "2013-07-30"}''

Si lo desea, más adelante puede agregar otros casos especiales a esto con un simple giro del método default . Ejemplo:

def default(o): if type(o) is datetime.date or type(o) is datetime.datetime: return o.isoformat() if type(o) is decimal.Decimal: return float(o)


Mi solución ...

Class Puppy(Base): ... @property def serialize(self): return { ''id'':self.id, ''date_birth'':self.date_birth, ... }

Ok, ahora algunas pruebas.

... ''date_birth'':self.date_birth.isoformat(), ...


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

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


Para otras personas que no necesitan o desean usar la biblioteca pymongo para esto ... puede lograr la conversión JSON datetime fácilmente con este pequeño fragmento de código:

def default(obj): """Default JSON serializer.""" import calendar, datetime if isinstance(obj, datetime.datetime): if obj.utcoffset() is not None: obj = obj - obj.utcoffset() millis = int( calendar.timegm(obj.timetuple()) * 1000 + obj.microsecond / 1000 ) return millis raise TypeError(''Not sure how to serialize %s'' % (obj,))

Entonces utilízalo así:

import datetime, json print json.dumps(datetime.datetime.now(), default=default)

salida:

''1365091796124''


Prueba este con un ejemplo para analizarlo:

#!/usr/bin/env python import datetime import json import dateutil.parser # pip install python-dateutil class JSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): return obj.isoformat() return super(JSONEncoder, self).default(obj) def test(): dts = [ datetime.datetime.now(), datetime.datetime.now(datetime.timezone(-datetime.timedelta(hours=4))), datetime.datetime.utcnow(), datetime.datetime.now(datetime.timezone.utc), ] for dt in dts: dt_isoformat = json.loads(json.dumps(dt, cls=JSONEncoder)) dt_parsed = dateutil.parser.parse(dt_isoformat) assert dt == dt_parsed print(f''{dt}, {dt_isoformat}, {dt_parsed}'') # 2018-07-22 02:22:42.910637, 2018-07-22T02:22:42.910637, 2018-07-22 02:22:42.910637 # 2018-07-22 02:22:42.910643-04:00, 2018-07-22T02:22:42.910643-04:00, 2018-07-22 02:22:42.910643-04:00 # 2018-07-22 06:22:42.910645, 2018-07-22T06:22:42.910645, 2018-07-22 06:22:42.910645 # 2018-07-22 06:22:42.910646+00:00, 2018-07-22T06:22:42.910646+00:00, 2018-07-22 06:22:42.910646+00:00 if __name__ == ''__main__'': test()


Puede que no sea 100% correcto, pero esta es la forma más sencilla de serializar

#!/usr/bin/python import datetime,json sampledict = {} sampledict[''a''] = "some string" sampledict[''b''] = datetime.datetime.now() print sampledict # output : {''a'': ''some string'', ''b'': datetime.datetime(2017, 4, 15, 5, 15, 34, 652996)} #print json.dumps(sampledict) '''''' output : Traceback (most recent call last): File "./jsonencodedecode.py", line 10, in <module> print json.dumps(sampledict) File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps return _default_encoder.encode(obj) File "/usr/lib/python2.7/json/encoder.py", line 207, in encode chunks = self.iterencode(o, _one_shot=True) File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode return _iterencode(o, 0) File "/usr/lib/python2.7/json/encoder.py", line 184, in default raise TypeError(repr(o) + " is not JSON serializable") TypeError: datetime.datetime(2017, 4, 15, 5, 16, 17, 435706) is not JSON serializable '''''' sampledict[''b''] = datetime.datetime.now().strftime("%B %d, %Y %H:%M %p") afterdump = json.dumps(sampledict) print afterdump #output : {"a": "some string", "b": "April 15, 2017 05:18 AM"} print type(afterdump) #<type ''str''> afterloads = json.loads(afterdump) print afterloads # output : {u''a'': u''some string'', u''b'': u''April 15, 2017 05:18 AM''} print type(afterloads) # output :<type ''dict''>


Recibí el mismo mensaje de error al escribir el decorador serializar dentro de una clase con sqlalchemy. Así que en lugar de:

for key,val in sample.items(): if isinstance(val, datetime): sample[key] = ''{:%Y-%m-%d %H:%M:%S}''.format(val) #you can add different formating here json.dumps(sample)

Simplemente tomé prestada la idea de jgbarah de usar isoformat () y adjunté el valor original con isoformat (), para que ahora parezca:

def myconverter(o): if isinstance(o, datetime.datetime): return o.__str__() print(json.dumps(d, default = myconverter))


Si está utilizando el resultado en una vista, asegúrese de devolver una respuesta adecuada. Según la API, jsonify hace lo siguiente:

Crea una Respuesta con la representación JSON de los argumentos dados con una aplicación / json mimetype.

Para imitar este comportamiento con json.dumps, debe agregar algunas líneas de código adicionales.

response = make_response(dumps(sample, cls=CustomEncoder)) response.headers[''Content-Type''] = ''application/json'' response.headers[''mimetype''] = ''application/json'' return response

También debe devolver un dict para replicar completamente la respuesta de jsonify. Así, todo el archivo se verá así

from flask import make_response from json import JSONEncoder, dumps class CustomEncoder(JSONEncoder): def default(self, obj): if set([''quantize'', ''year'']).intersection(dir(obj)): return str(obj) elif hasattr(obj, ''next''): return list(obj) return JSONEncoder.default(self, obj) @app.route(''/get_reps/'', methods=[''GET'']) def get_reps(): sample = [''some text'', <datetime object>, 123] response = make_response(dumps({''result'': sample}, cls=CustomEncoder)) response.headers[''Content-Type''] = ''application/json'' response.headers[''mimetype''] = ''application/json'' return response


Si se encuentra en ambos lados de la comunicación, puede usar las funciones repr () y eval () junto con json.

#!/usr/bin/env python3.7 from datetime import datetime from datetime import timezone from datetime import timedelta import json def default(obj): if isinstance(obj, datetime): return { ''_isoformat'': obj.isoformat() } return super().default(obj) def object_hook(obj): _isoformat = obj.get(''_isoformat'') if _isoformat is not None: return datetime.fromisoformat(_isoformat) return obj if __name__ == ''__main__'': #d = { ''now'': datetime(2000, 1, 1) } d = { ''now'': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) } s = json.dumps(d, default=default) print(s) print(d == json.loads(s, object_hook=object_hook))

No deberías importar datetime como

{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}} True

ya que eval se quejará. O puede pasar datetime como un parámetro para evaluar. En cualquier caso esto debería funcionar.


Sobre la base de otras respuestas, una solución simple basada en un serializador específico que simplemente convierte los objetos datetime.datetime y datetime.date en 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 simplemente comprueba si el objeto es de la clase datetime.datetime o datetime.date , y luego usa .isoformat() para producir una versión serializada del mismo, de acuerdo con el formato ISO 8601, YYYY-MM-DDTHH: MM: SS (que es fácilmente decodificado por JavaScript). Si se buscan representaciones seriadas 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 finaliza al generar una excepción, para tratar el caso en que se llama 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 para json.dumps se pueden encontrar en la sección Uso básico de la documentación del módulo json .


Tengo una aplicación con un problema similar; mi enfoque fue JSONize el valor de fecha y hora como una lista de 6 elementos (año, mes, día, hora, minutos, segundos); podría ir a microsegundos como una lista de 7 elementos, pero no tenía necesidad de:

class DateTimeEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): encoded_object = list(obj.timetuple())[0:6] else: encoded_object =json.JSONEncoder.default(self, obj) return encoded_object sample = {} sample[''title''] = "String" sample[''somedate''] = datetime.datetime.now() print sample print json.dumps(sample, cls=DateTimeEncoder)

produce:

{''somedate'': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), ''title'': ''String''} {"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}


Una solución rápida si quieres tu propio formato.

import datetime, json dt = datetime.datetime.now() print("This is now: {}".format(dt)) dt1 = json.dumps(repr(dt)) print("This is serialised: {}".format(dt1)) dt2 = json.loads(dt1) print("This is loaded back from json: {}".format(dt2)) dt3 = eval(dt2) print("This is the same object as we started: {}".format(dt3)) print("Check if they are equal: {}".format(dt == dt3))


si está usando python3.7, entonces la mejor solución es usar datetime.isoformat() y datetime.fromisoformat() ; trabajan con objetos de datetime y datetime ingenuos y conscientes:

from datetime import datetime import json from pytz import timezone import pytz def json_dt_serializer(obj): """JSON serializer, by macm. """ rsp = dict() if isinstance(obj, datetime): rsp[''day''] = obj.day rsp[''hour''] = obj.hour rsp[''microsecond''] = obj.microsecond rsp[''minute''] = obj.minute rsp[''month''] = obj.month rsp[''second''] = obj.second rsp[''year''] = obj.year rsp[''tzinfo''] = str(obj.tzinfo) return rsp raise TypeError("Type not serializable") def json_dt_deserialize(obj): """JSON deserialize from json_dt_serializer, by macm. """ if isinstance(obj, str): obj = json.loads(obj) tzone = timezone(obj[''tzinfo'']) tmp_dt = datetime(obj[''year''], obj[''month''], obj[''day''], hour=obj[''hour''], minute=obj[''minute''], second=obj[''second''], microsecond=obj[''microsecond'']) loc_dt = tzone.localize(tmp_dt) deserialize = loc_dt.astimezone(tzone) return deserialize

salida:

# Tests now = datetime.now(pytz.utc) # Using this solution rsp = json_dt_serializer(now) tmp = json_dt_deserialize(rsp) assert tmp == now assert isinstance(tmp, datetime) == True assert isinstance(now, datetime) == True # using default from json.dumps tmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer) rsp = json_dt_deserialize(tmp) assert isinstance(rsp, datetime) == True # Lets try another timezone eastern = timezone(''US/Eastern'') now = datetime.now(eastern) rsp = json_dt_serializer(now) tmp = json_dt_deserialize(rsp) print(tmp) # 2015-10-22 09:18:33.169302-04:00 print(now) # 2015-10-22 09:18:33.169302-04:00 # Wow, Works! assert tmp == now

si está usando python3.6 o inferior, y solo le importa el valor del tiempo (no la zona horaria), puede usar datetime.timestamp() y datetime.fromtimestamp() lugar;

Si está usando python3.6 o inferior, y le preocupa la zona horaria, puede obtenerla a través de datetime.tzinfo , pero tiene que serializar este campo por sí mismo. la forma más sencilla de hacerlo es agregar otro campo _tzinfo en el objeto serializado;

Finalmente, ten cuidado con las precisiones en todos estos ejemplos;


json.dumps proporcionar una clase de codificador personalizada con el parámetro cls de json.dumps . Para citar de los docs :

>>> import json >>> class ComplexEncoder(json.JSONEncoder): ... def default(self, obj): ... if isinstance(obj, complex): ... return [obj.real, obj.imag] ... return json.JSONEncoder.default(self, obj) ... >>> dumps(2 + 1j, cls=ComplexEncoder) ''[2.0, 1.0]'' >>> ComplexEncoder().encode(2 + 1j) ''[2.0, 1.0]'' >>> list(ComplexEncoder().iterencode(2 + 1j)) [''['', ''2.0'', '', '', ''1.0'', '']'']

Esto utiliza números complejos como ejemplo, pero puede crear una clase para codificar fechas con la misma facilidad (excepto que creo que JSON está un poco confuso respecto a las fechas)


def j_serial(o): # self contained from datetime import datetime, date return str(o).split(''.'')[0] if isinstance(o, (datetime, date)) else None

Uso de la utilidad anterior:

import datetime serial_d = j_serial(datetime.datetime.now()) if serial_d: print(serial_d) # output: 2018-02-28 02:23:15