Ich habe ein grundlegendes Diktat wie folgt:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
Wenn ich es versuche, jsonify(sample)
bekomme ich:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
Was kann ich tun, damit mein Wörterbuchbeispiel den oben genannten Fehler beheben kann?
Hinweis: Obwohl dies möglicherweise nicht relevant ist, werden die Wörterbücher aus dem Abrufen von Datensätzen generiert, aus mongodb
denen beim Ausdrucken str(sample['somedate'])
die Ausgabe erfolgt 2012-08-08 21:46:24.862000
.
Antworten:
Aktualisiert für 2018
Die ursprüngliche Antwort entsprach der Darstellung der MongoDB-Datumsfelder als:
{"$date": 1506816000000}
Wenn Sie eine generische Python-Lösung für die Serialisierung
datetime
nach json wünschen , lesen Sie die Antwort von @jjmontes, um eine schnelle Lösung zu finden, für die keine Abhängigkeiten erforderlich sind.Da Sie Mongoengine verwenden (laut Kommentaren) und Pymongo eine Abhängigkeit ist, verfügt Pymongo über integrierte Dienstprogramme, die bei der JSON-Serialisierung helfen:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html
Anwendungsbeispiel (Serialisierung):
Anwendungsbeispiel (Deserialisierung):
Django
Django bietet einen nativen
DjangoJSONEncoder
Serializer, der diese Art von richtig behandelt.Siehe https://docs.djangoproject.com/de/dev/topics/serialization/#djangojsonencoder
Ein Unterschied, den ich zwischen der
DjangoJSONEncoder
Verwendung eines solchen Brauchs festgestellt habedefault
:Ist das, dass Django ein bisschen von den Daten entfernt:
In einigen Fällen müssen Sie daher vorsichtig sein.
quelle
Django MongoDB
. Mit dem späteren würden Sie versuchen, innerhalb des Django-ORM zu bleiben, um den agnostischen Zustand des Backends aufrechtzuerhalten. Aber manchmal kann man nicht das tun, was man in der Abstraktion braucht, also lässt man eine Ebene fallen. In diesem Fall hat dies nichts mit Ihrem Problem zu tun, da Sie nur Dienstprogrammmethoden verwenden, um das JSON-Format zu begleiten.Mein schneller und schmutziger JSON-Dump, der Datteln und alles frisst:
quelle
default
ist eine Funktion, die auf Objekte angewendet wird, die nicht serialisierbar sind. In diesem Fallstr
konvertiert es einfach alles, was es nicht weiß, in Zeichenfolgen. Das ist großartig für die Serialisierung, aber nicht so großartig beim Deserialisieren (daher das "Quick & Dirty"), da alles ohne Vorwarnung mit einem String versehen werden könnte, z. B. eine Funktion oder ein Numpy-Array.json.dumps({():1,type(None):2},default=str)
erhöhtTypeError
, kann Typ oder Tupel nicht haben.Aufbauend auf anderen Antworten eine einfache Lösung, die auf einem bestimmten Serializer basiert, der nur Zeichenfolgen konvertiert
datetime.datetime
unddatetime.date
in Zeichenfolgen umwandelt .Wie zu sehen ist, prüft der Code nur, ob das Objekt der Klasse
datetime.datetime
oder entsprichtdatetime.date
, und erstellt dann.isoformat()
eine serialisierte Version davon gemäß dem ISO 8601-Format JJJJ-MM-TTTHH: MM: SS (das mit JavaScript leicht dekodiert werden kann) ). Wenn komplexere serialisierte Darstellungen gesucht werden, kann anstelle von str () ein anderer Code verwendet werden (Beispiele finden Sie in den anderen Antworten auf diese Frage). Der Code endet mit dem Auslösen einer Ausnahme, um den Fall zu behandeln, dass er mit einem nicht serialisierbaren Typ aufgerufen wird.Diese json_serial-Funktion kann wie folgt verwendet werden:
Einzelheiten zur Funktionsweise des Standardparameters für json.dumps finden Sie im Abschnitt Grundlegende Verwendung der Dokumentation zum json-Modul .
quelle
01:00:00+01:00
und02:00:00+00:00
sollten je nach Kontext nicht gleich sein. Sie beziehen sich natürlich auf denselben Zeitpunkt, aber der Versatz kann ein relevanter Aspekt des Werts sein.Ich bin gerade auf dieses Problem gestoßen und meine Lösung besteht in der Unterklasse
json.JSONEncoder
:Machen Sie in Ihrem Anruf etwas wie:
json.dumps(yourobj, cls=DateTimeEncoder)
Das habe.isoformat()
ich aus einer der obigen Antworten erhalten.quelle
DjangoJSONEncoder
. docs.djangoproject.com/de/dev/topics/serialization/…return super(DateTimeEncoder, self).default(o)
return super().default(o)
Konvertieren Sie das Datum in eine Zeichenfolge
quelle
oDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f')
. Formate erhalten von: docs.python.org/2/library/datetime.html.now()
die Ortszeit verwendet wird, ohne dies anzugeben. Zumindest.utcnow()
sollte verwendet werden (und dann ein +0000 oder Z angehängt)At least .utcnow() should be used
Nicht genau,datetime.now(timezone.utc)
wird empfohlen, siehe Warnung in: docs.python.org/3.8/library/… .Für andere, die die Pymongo-Bibliothek dafür nicht benötigen oder verwenden möchten, können Sie mit diesem kleinen Snippet auf einfache Weise eine JSON-Konvertierung von Datum und Uhrzeit erreichen:
Dann benutze es so:
Ausgabe:
quelle
millis=
in der if-Anweisung eingerückt werden? Es ist wahrscheinlich auch besser, str (obj) zu verwenden, um das ISO-Format zu erhalten, das meiner Meinung nach häufiger vorkommt.datetime.now()
Gibt die Ortszeit zurück (als naives Datum / Uhrzeit-Objekt), aber Ihr Code geht davon aus, dass diesobj
in UTC ist, wenn es nicht zeitzonenbewusst ist. Verwenden Siedatetime.utcnow()
stattdessen.Hier ist meine Lösung:
Dann können Sie es so verwenden:
quelle
isinstance(obj, datetime.datetime)
innerhalb des TypeError weitere zu behandelnde Typen hinzufügen und mit demstr(obj)
oder abschließenrepr(obj)
. Und alle Ihre Dumps können nur auf diese spezialisierte Klasse verweisen.Ich habe eine Bewerbung mit einem ähnlichen Problem. Mein Ansatz war es, den Datum / Uhrzeit-Wert als Liste mit 6 Elementen (Jahr, Monat, Tag, Stunde, Minuten, Sekunden) zu JSONisieren. Sie könnten als 7-Punkte-Liste auf Mikrosekunden gehen, aber ich musste nicht:
produziert:
quelle
Meine Lösung (mit weniger Ausführlichkeit, denke ich):
Dann verwenden Sie
jsondumps
anstelle vonjson.dumps
. Es wird gedruckt:Wenn Sie möchten, können Sie später mit einer einfachen Änderung der
default
Methode weitere Sonderfälle hinzufügen . Beispiel:quelle
Dieses Q wird immer wieder wiederholt - eine einfache Möglichkeit, das JSON-Modul so zu patchen, dass die Serialisierung datetime unterstützt.
Verwenden Sie dann wie immer die JSON-Serialisierung - diesmal mit datetime als Isoformat.
Ergebnis: '{"created": "2015-08-26T14: 21: 31.853855"}'
Weitere Details und einige Hinweise zur Vorsicht finden Sie unter: StackOverflow: JSON-Datumszeit zwischen Python und JavaScript
quelle
Die Methode json.dumps kann einen optionalen Parameter namens default akzeptieren, von dem erwartet wird, dass er eine Funktion ist. Jedes Mal, wenn JSON versucht, einen Wert zu konvertieren, weiß es nicht, wie es konvertiert werden soll, wird die Funktion aufgerufen, die wir an ihn übergeben haben. Die Funktion empfängt das betreffende Objekt und es wird erwartet, dass die JSON-Darstellung des Objekts zurückgegeben wird.
quelle
Wenn Sie Python3.7 verwenden, ist die beste Lösung die Verwendung von
datetime.isoformat()
unddatetime.fromisoformat()
; Sie arbeiten sowohl mit naiven als auch mit bewusstendatetime
Objekten:Ausgabe:
Wenn Sie Python3.6 oder niedriger verwenden und sich nur um den Zeitwert (nicht um die Zeitzone) kümmern, können Sie stattdessen
datetime.timestamp()
unddatetime.fromtimestamp()
verwenden.Wenn Sie Python3.6 oder niedriger verwenden und sich für die Zeitzone interessieren, können Sie diese über abrufen
datetime.tzinfo
, aber Sie müssen dieses Feld selbst serialisieren. Der einfachste Weg, dies zu tun, besteht darin,_tzinfo
dem serialisierten Objekt ein weiteres Feld hinzuzufügen .Achten Sie schließlich auf die Präzision in all diesen Beispielen.
quelle
Sie sollten
.strftime()
method on.datetime.now()
method verwenden, um es als serialisierbare Methode zu erstellen .Hier ist ein Beispiel:
Ausgabe:
quelle
Hier ist eine einfache Lösung, um das Problem "datetime not JSON serializable" zu überwinden.
Ausgabe: -> {"Datum": "2015-12-16T04: 48: 20.024609"}
quelle
Sie müssen eine benutzerdefinierte Encoderklasse mit dem
cls
Parameter von angebenjson.dumps
. Um aus den Dokumenten zu zitieren :Dies verwendet komplexe Zahlen als Beispiel, aber Sie können genauso einfach eine Klasse zum Codieren von Datumsangaben erstellen (außer ich denke, JSON ist ein wenig verschwommen in Bezug auf Datumsangaben).
quelle
Der einfachste Weg, dies zu tun, besteht darin, den Teil des Diktats im Datum / Uhrzeit-Format in Isoformat zu ändern. Dieser Wert ist effektiv eine Zeichenfolge in isoformat, mit der json einverstanden ist.
quelle
Eigentlich ist es ganz einfach. Wenn Sie Datumsangaben häufig serialisieren müssen, arbeiten Sie mit ihnen als Zeichenfolgen. Sie können sie bei Bedarf problemlos als Datums- / Uhrzeitobjekte zurückkonvertieren.
Wenn Sie hauptsächlich als datetime-Objekte arbeiten müssen, konvertieren Sie sie vor der Serialisierung als Zeichenfolgen.
Wie Sie sehen, ist die Ausgabe in beiden Fällen gleich. Nur der Typ ist unterschiedlich.
quelle
Wenn Sie das Ergebnis in einer Ansicht verwenden, müssen Sie eine ordnungsgemäße Antwort zurückgeben. Laut API führt jsonify Folgendes aus:
Um dieses Verhalten mit json.dumps nachzuahmen, müssen Sie einige zusätzliche Codezeilen hinzufügen.
Sie sollten auch ein Diktat zurückgeben, um die Antwort von jsonify vollständig zu replizieren. Die gesamte Datei sieht also so aus
quelle
pymongo
.Versuchen Sie dieses mit einem Beispiel, um es zu analysieren:
quelle
Meine Lösung ...
Ok, jetzt ein paar Tests.
quelle
Hier ist meine vollständige Lösung für die Konvertierung von datetime in JSON und zurück.
Ausgabe
JSON-Datei
Dadurch konnte ich Zeichenfolgen, Ints, Floats und Datetime-Objekte importieren und exportieren. Es sollte nicht zu schwer sein, für andere Typen zu erweitern.
quelle
TypeError: 'str' does not support the buffer interface
. Es liegt am'wb'
offenen Modus, sollte sein'w'
. Es kommt auch zu einer Deserialisierung, wenn wir Daten haben, die dem Datum ähnlich sind,'0000891618-05-000338'
aber nicht mit dem Muster übereinstimmen.Konvertieren Sie die
date
instring
quelle
Im Allgemeinen gibt es verschiedene Möglichkeiten, Datumsangaben zu serialisieren:
Wenn Sie mit dem letzten Weg einverstanden sind , verarbeitet das Paket json_tricks Datums-, Uhrzeit- und Datumsangaben einschließlich Zeitzonen.
was gibt:
Alles was Sie tun müssen, ist
und dann importieren von
json_tricks
stattjson
.Der Vorteil, dass es nicht als einzelne Zeichenfolge, int oder float gespeichert wird, ergibt sich beim Decodieren: Wenn Sie nur auf eine Zeichenfolge oder insbesondere auf int oder float stoßen, müssen Sie etwas über die Daten wissen, um zu wissen, ob es sich um eine Datums- / Uhrzeitangabe handelt. Als Diktat können Sie Metadaten speichern, damit sie automatisch dekodiert werden können, was
json_tricks
für Sie der Fall ist. Es ist auch leicht für Menschen bearbeitbar.Haftungsausschluss: Es ist von mir gemacht. Weil ich das gleiche Problem hatte.
quelle
Ich habe die gleiche Fehlermeldung erhalten, als ich den Serialize Decorator in eine Klasse mit SQLalchemy geschrieben habe. Also statt:
Ich habe mir einfach die Idee von jgbarah geliehen, isoformat () zu verwenden, und den ursprünglichen Wert mit isoformat () angehängt, so dass es jetzt so aussieht:
quelle
Eine schnelle Lösung, wenn Sie Ihre eigene Formatierung wünschen
quelle
Wenn Sie sich auf beiden Seiten der Kommunikation befinden, können Sie die Funktionen repr () und eval () zusammen mit json verwenden.
Sie sollten datetime nicht als importieren
da wird sich eval beschweren. Oder Sie können datetime als Parameter an eval übergeben. In jedem Fall sollte dies funktionieren.
quelle
Ich hatte das gleiche Problem beim Externalisieren des Django-Modellobjekts als JSON festgestellt. Hier ist, wie Sie es lösen können.
quelle
Verwendung des oben genannten Dienstprogramms:
quelle
Diese Bibliothek Superjson kann es tun. Sie können den JSON-Serializer ganz einfach für Ihr eigenes Python-Objekt anpassen, indem Sie dieser Anweisung folgen: https://superjson.readthedocs.io/index.html#extend .
Das allgemeine Konzept lautet:
Ihr Code muss die richtige Serialisierungs- / Deserialisierungsmethode basierend auf dem Python-Objekt finden. Normalerweise ist der vollständige Klassenname eine gute Kennung.
Und dann sollte Ihre ser / deser-Methode in der Lage sein, Ihr Objekt in ein reguläres serialisierbares Json-Objekt umzuwandeln, eine Kombination aus generischem Python-Typ, Diktat, Liste, Zeichenfolge, Int, Float. Und implementieren Sie Ihre Deser-Methode umgekehrt.
quelle
Ich kann nicht 100% richtig sein, aber dies ist der einfache Weg, um zu serialisieren
quelle