Mam podstawowy dykt, jak następuje:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
Kiedy próbuję to zrobić jsonify(sample)
, dostaję:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
Co mogę zrobić, aby moja próbka słownika mogła przezwyciężyć powyższy błąd?
Uwaga: Chociaż może to nie być istotne, słowniki są generowane na podstawie wyszukiwania rekordów, z mongodb
których, kiedy drukuję str(sample['somedate'])
, wynik jest 2012-08-08 21:46:24.862000
.
Odpowiedzi:
Zaktualizowano w 2018 r
Oryginalna odpowiedź uwzględniała sposób, w jaki pola „daty” MongoDB były reprezentowane jako:
{"$date": 1506816000000}
Jeśli potrzebujesz ogólnego rozwiązania Python do serializacji
datetime
do json, sprawdź odpowiedź @jjmontes, aby znaleźć szybkie rozwiązanie, które nie wymaga żadnych zależności.Ponieważ używasz mongoengine (na komentarze), a pymongo jest zależnością, pymongo ma wbudowane narzędzia do pomocy w serializacji json:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html
Przykładowe użycie (serializacja):
Przykładowe użycie (deserializacja):
Django
Django zapewnia natywny
DjangoJSONEncoder
serializator, który poprawnie radzi sobie z tego rodzaju.Zobacz https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder
Zauważyłem jedną różnicę między
DjangoJSONEncoder
używaniem niestandardowegodefault
typu takiego:Czy Django usuwa trochę danych:
W niektórych przypadkach może być konieczne zachowanie ostrożności.
źródło
Django MongoDB
. W późniejszym okresie próbujesz pozostać w ramach ORM django, aby utrzymać stan agnostyczny zaplecza. Ale czasami nie możesz zrobić tego, czego potrzebujesz w abstrakcji, więc upuszczasz warstwę. W tym przypadku jest to całkowicie niezwiązane z twoim problemem, ponieważ po prostu używasz metod użyteczności, aby towarzyszyć formatowi JSON.Mój szybki i brudny zrzut JSON, który zjada daty i wszystko:
źródło
default
to funkcja stosowana do obiektów, których nie można serializować. W tym przypadku jeststr
tak, więc po prostu konwertuje wszystko, czego nie wie, na ciągi. Co jest świetne w przypadku serializacji, ale nie tak świetne podczas deserializacji (stąd „szybkie i brudne”), ponieważ wszystko mogło być ciągiem znaków bez ostrzeżenia, np. Funkcja lub tablica liczb.json.dumps({():1,type(None):2},default=str)
podbiciaTypeError
, nie może mieć typ lub krotki.Opierając się na innych odpowiedziach, proste rozwiązanie oparte na konkretnym serializatorze, który po prostu konwertuje
datetime.datetime
idatetime.date
obiektów na ciągi.Jak widać, kod tylko kontrole, aby dowiedzieć się, czy obiekt jest klasy
datetime.datetime
lubdatetime.date
, a następnie wykorzystuje.isoformat()
do produkcji odcinkach wersję nim, zgodnie z formatem ISO 8601, yyyy-MM-DDTgg: MM: SS (co jest łatwo dekodowane przez JavaScript ). Jeśli poszukiwane są bardziej złożone serializacje, zamiast str () można użyć innego kodu (przykłady można znaleźć w innych odpowiedziach na to pytanie). Kod kończy się zgłoszeniem wyjątku, aby poradzić sobie z przypadkiem, który jest wywoływany z typem, który nie jest serializowany.Z tej funkcji json_serial można korzystać w następujący sposób:
Szczegółowe informacje na temat działania domyślnego parametru json.dumps można znaleźć w sekcji Podstawowe użycie dokumentacji modułu json .
źródło
01:00:00+01:00
i02:00:00+00:00
które nie powinny być takie same, w zależności od kontekstu. Odnoszą się one do tego samego punktu w czasie, ale przesunięcie może być istotnym aspektem wartości.Właśnie napotkałem ten problem i moim rozwiązaniem jest podklasa
json.JSONEncoder
:W wywołaniu zrobić coś takiego:
json.dumps(yourobj, cls=DateTimeEncoder)
The.isoformat()
dostałem od jednego z powyższych odpowiedzi.źródło
DjangoJSONEncoder
. docs.djangoproject.com/en/dev/topics/serialization/…return super(DateTimeEncoder, self).default(o)
return super().default(o)
Konwertuj datę na ciąg
źródło
oDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f')
. Formaty uzyskane z: docs.python.org/2/library/datetime.html.now()
używa czasu lokalnego, bez zaznaczania tego. Przynajmniej.utcnow()
należy użyć (a następnie dołączyć +0000 lub Z)At least .utcnow() should be used
Niezupełnie,datetime.now(timezone.utc)
jest zalecane, patrz ostrzeżenie w: docs.python.org/3.8/library/… .Dla innych, którzy nie potrzebują lub nie chcą w tym celu korzystać z biblioteki pymongo .. można łatwo uzyskać konwersję JSON datetime za pomocą tego małego fragmentu:
Następnie użyj go w następujący sposób:
wynik:
źródło
millis=
być wcięte wewnątrz instrukcji if? Prawdopodobnie lepiej jest również użyć str (obj), aby uzyskać format ISO, który moim zdaniem byłby bardziej powszechny.datetime.now()
zwraca czas lokalny (jako naiwny obiekt typu data-godzina), ale twój kod zakłada, żeobj
jest w UTC, jeśli nie obsługuje strefy czasowej. Użyjdatetime.utcnow()
zamiast tego.Oto moje rozwiązanie:
Następnie możesz użyć go w ten sposób:
źródło
isinstance(obj, datetime.datetime)
w TypeError, dodać więcej typów do obsługi i zakończyć za pomocąstr(obj)
lubrepr(obj)
. I wszystkie zrzuty mogą po prostu wskazywać na tę wyspecjalizowaną klasę.Mam aplikację z podobnym problemem; moim podejściem było JSONize wartości datetime jako listy 6-elementowej (rok, miesiąc, dzień, godzina, minuty, sekundy); możesz przejść do mikrosekund jako listy 7-elementowej, ale nie musiałem:
produkuje:
źródło
Moje rozwiązanie (chyba mniej gadatliwe):
Następnie użyj
jsondumps
zamiastjson.dumps
. Wydrukuje:Chcę, później możesz dodać do tego inne specjalne przypadki za pomocą prostej zmiany
default
metody. Przykład:źródło
To Q powtarza się raz po raz - prosty sposób na załatanie modułu json tak, aby serializacja obsługiwała datetime.
Następnie używaj serializacji json jak zawsze - tym razem z serializacją daty i godziny jako izoformatu.
Wynik: „{„ utworzono ”:„ 2015-08-26T14: 21: 31.853855 ”}”
Zobacz więcej szczegółów i kilka ostrzeżeń na: StackOverflow: JSON datetime między Pythonem a JavaScript
źródło
Metoda json.dumps może zaakceptować opcjonalny parametr o nazwie default, który ma być funkcją. Za każdym razem, gdy JSON próbuje przekonwertować wartość, nie wie, jak ją przekonwertować, wywoła przekazaną nam funkcję. Funkcja otrzyma przedmiotowy obiekt i oczekuje się, że zwróci reprezentację JSON obiektu.
źródło
jeśli używasz python3.7, najlepszym rozwiązaniem jest użycie
datetime.isoformat()
idatetime.fromisoformat()
; pracują zdatetime
obiektami zarówno naiwnymi, jak i świadomymi :wynik:
jeśli używasz Python3.6 lub niższej wersji i zależy ci tylko na wartości czasu (nie strefie czasowej), możesz użyć
datetime.timestamp()
idatetime.fromtimestamp()
zamiast;jeśli używasz Python3.6 lub niższej wersji i zależy ci na strefie czasowej, możesz to zrobić
datetime.tzinfo
, ale musisz samodzielnie serializować to pole; najłatwiej to zrobić, dodając kolejne pole_tzinfo
w serializowanym obiekcie;na koniec strzeżcie się precyzji we wszystkich tych przykładach;
źródło
Powinieneś użyć
.strftime()
metody na.datetime.now()
metodzie, aby uczynić ją metodą szeregowalną .Oto przykład:
Wynik:
źródło
Oto proste rozwiązanie istniejącego problemu „dataetime not JSON serializable”.
Dane wyjściowe: -> {„data”: „2015-12-16T04: 48: 20.024609”}
źródło
Musisz podać niestandardową klasę enkodera z
cls
parametremjson.dumps
. Cytując z dokumentów :W tym przykładzie użyto liczb zespolonych, ale równie łatwo można utworzyć klasę do kodowania dat (z wyjątkiem tego, że JSON jest trochę rozmyślny na temat dat)
źródło
Najprostszym sposobem na to jest zmiana części nagrania w formacie datetime na izoformat. Ta wartość będzie efektywnie ciągiem znaków w izoformacie, z którym json jest w porządku.
źródło
W rzeczywistości jest to dość proste. Jeśli musisz często serializować daty, pracuj z nimi jako ciągami znaków. W razie potrzeby możesz łatwo przekonwertować je z powrotem jako obiekty daty i godziny.
Jeśli chcesz pracować głównie jako obiekty datetime, przekonwertuj je jako ciągi przed serializacją.
Jak widać, wynik jest taki sam w obu przypadkach. Tylko typ jest inny.
źródło
Jeśli używasz wyniku w widoku, pamiętaj o zwróceniu prawidłowej odpowiedzi. Zgodnie z interfejsem API, jsonify wykonuje następujące czynności:
Aby naśladować to zachowanie za pomocą json.dumps, musisz dodać kilka dodatkowych wierszy kodu.
Powinieneś również zwrócić dyktando, aby w pełni replikować odpowiedź jsonify. Cały plik będzie więc wyglądał tak
źródło
pymongo
.Spróbuj tego z przykładem, aby go przeanalizować:
źródło
Moje rozwiązanie ...
Ok, teraz kilka testów.
źródło
Oto moje pełne rozwiązanie do konwersji datetime na JSON iz powrotem.
Wynik
Plik JSON
To pozwoliło mi importować i eksportować ciągi, inty, zmiennoprzecinkowe i obiekty datetime. Nie powinno być trudno rozszerzyć na inne typy.
źródło
TypeError: 'str' does not support the buffer interface
. To z powodu'wb'
trybu otwartego powinno być'w'
. Uderza również w deserializację, gdy mamy dane podobne do daty, takie jak,'0000891618-05-000338'
ale nie pasujące do wzorca.Konwertuj
date
nastring
źródło
Zasadniczo istnieje szereg sposobów serializacji czasów danych, takich jak:
Jeśli nie masz nic przeciwko temu, pakiet json_tricks obsługuje daty, godziny i czasy danych, w tym strefy czasowe.
co daje:
Więc wszystko, co musisz zrobić, to
a następnie zaimportuj z
json_tricks
zamiastjson
.Zaleta polegająca na tym, że nie jest przechowywana jako pojedynczy ciąg, liczba całkowita lub liczba zmiennoprzecinkowa, pojawia się podczas dekodowania: jeśli napotkasz tylko ciąg znaków, a szczególnie wartość całkowitą lub zmiennoprzecinkową, musisz wiedzieć coś o danych, aby wiedzieć, czy jest to data i godzina. W przypadku nagrania można przechowywać metadane, aby można je było dekodować automatycznie, czyli co
json_tricks
dla Ciebie . Można go również łatwo edytować dla ludzi.Zastrzeżenie: jest wykonane przeze mnie. Ponieważ miałem ten sam problem.
źródło
Otrzymałem ten sam komunikat o błędzie podczas pisania serializatora w klasie z sqlalchemy. Więc zamiast:
Po prostu pożyczyłem pomysł jgbarah na użycie isoformat () i dołączyłem pierwotną wartość do isoformat (), aby teraz wyglądało to tak:
źródło
Szybka poprawka, jeśli chcesz mieć własne formatowanie
źródło
Jeśli jesteś po obu stronach komunikacji, możesz używać funkcji repr () i eval () wraz z json.
Nie należy importować daty i godziny jako
ponieważ eval będzie narzekać. Lub możesz przekazać datetime jako parametr do oceny. W każdym razie powinno to działać.
źródło
Napotkałem ten sam problem podczas uzewnętrzniania obiektu modelu django w celu zrzutu jako JSON. Oto jak możesz to rozwiązać.
źródło
Zastosowanie powyższego narzędzia:
źródło
Superjson biblioteki może to zrobić. I możesz z łatwością dostosować serializator json do własnego obiektu Python, postępując zgodnie z tą instrukcją https://superjson.readthedocs.io/index.html#extend .
Ogólna koncepcja to:
Twój kod musi znaleźć właściwą metodę serializacji / deserializacji na podstawie obiektu Pythona. Zwykle pełna nazwa klasy jest dobrym identyfikatorem.
Następnie twoja metoda ser / deser powinna być w stanie przekształcić obiekt w zwykły obiekt szeregowalny Json, kombinacja ogólnego typu python, dict, list, string, int, float. I zaimplementuj swoją metodę dezerteracji odwrotnie.
źródło
Może nie w 100% poprawne, ale jest to prosty sposób na serializację
źródło