1266 Stimmen

Wie kann man "datetime.datetime nicht JSON-seriellisierbar" überwinden?

Ich habe ein grundlegendes Wörterbuch wie folgt:

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

Wenn ich versuche, jsonify(sample) auszuführen, erhalte ich:

TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) ist nicht JSON-fähig

Was kann ich tun, damit mein Wörterbuch "sample" den oben genannten Fehler überwinden kann?

Hinweis: Obwohl es möglicherweise nicht relevant ist, werden die Wörterbücher aus dem Abrufen von Datensätzen aus mongodb generiert, bei dem, wenn ich str(sample['somedate']) ausdrucke, die Ausgabe 2012-08-08 21:46:24.862000 ist.

1482voto

jjmontes Punkte 19989

Mein schneller & schmutziger JSON-Dump, der Daten und alles frisst:

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

default ist eine Funktion, die auf nicht serialisierbare Objekte angewendet wird.
In diesem Fall ist es str, so dass es einfach alles, was es nicht kennt, in Strings umwandelt. Das ist großartig für die Serialisierung, aber nicht so toll beim Deserialisieren (daher das "schnell & schmutzig"), da alles ohne Warnung in Strings umgewandelt sein könnte, z.B. eine Funktion oder ein numpy-Array.

578voto

jgbarah Punkte 6466

Basierend auf anderen Antworten ist eine einfache Lösung auf einem spezifischen Serialisierer aufgebaut, der einfach datetime.datetime und datetime.date Objekte in Zeichenfolgen umwandelt.

from datetime import date, datetime

def json_serial(obj):
    """JSON-Serialisierer für Objekte, die standardmäßig nicht durch JSON-Code serialisierbar sind"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Typ %s nicht serialisierbar" % type(obj))

Wie man sieht, überprüft der Code einfach, ob das Objekt von der Klasse datetime.datetime oder datetime.date ist, und verwendet dann .isoformat(), um eine serialisierte Version davon gemäß ISO 8601-Format, JJJJ-MM-TTTHH:MM:SS (das von JavaScript leicht decodiert werden kann), zu erstellen. Wenn komplexere serialisierte Darstellungen gesucht werden, könnte anstelle von str() anderer Code verwendet werden (siehe andere Antworten auf diese Frage für Beispiele). Der Code endet, indem eine Ausnahme ausgelöst wird, um mit dem Fall umzugehen, dass er mit einem nicht serialisierbaren Typ aufgerufen wird.

Diese json_serial-Funktion kann wie folgt verwendet werden:

from datetime import datetime
from json import dumps

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

Weitere Informationen darüber, wie der Standardparameter für json.dumps funktioniert, finden Sie im Abschnitt Grundlegende Verwendung der Dokumentation des json-Moduls unter Abschnitt Grundlegende Verwendung der Dokumentation des json-Moduls.

532voto

jdi Punkte 86608

Aktualisiert für 2018

Die ursprüngliche Antwort wurde so angepasst, dass die MongoDB "date" Felder wie folgt dargestellt wurden:

{"$date": 1506816000000}

Wenn Sie eine generische Python-Lösung für die Serialisierung von datetime zu json möchten, schauen Sie sich @jjmontes' Antwort für eine schnelle Lösung an, die keine Abhängigkeiten erfordert.


Da Sie mongoengine verwenden (wie in den Kommentaren erwähnt) und pymongo eine Abhängigkeit ist, bietet pymongo eingebaute Hilfsprogramme zur Unterstützung der json-Serialisierung:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

Beispielverwendung (Serialisierung):

from bson import json_util
import json

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

Beispielverwendung (Deserialisierung):

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

Django

Django bietet einen nativen DjangoJSONEncoder-Serializer, der mit dieser Art von Daten ordnungsgemäß umgeht.

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

Ein Unterschied, den ich zwischen DjangoJSONEncoder und der Verwendung eines benutzerdefinierten default wie folgt festgestellt habe:

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
)

Ist, dass Django einen Teil der Daten entfernt:

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

Daher müssen Sie in einigen Fällen darauf achten.

277voto

lenny Punkte 2761

Ich bin gerade auf dieses Problem gestoßen und meine Lösung besteht darin, json.JSONEncoder zu unterklassifizieren:

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)

In Ihrem Aufruf machen Sie etwas wie: json.dumps(yourobj, cls=DateTimeEncoder) Das .isoformat() habe ich von einer der oben genannten Antworten.

142voto

D.A Punkte 2535

Datum in einen String umwandeln

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X