Saya memiliki perintah dasar sebagai berikut:
sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere
Ketika saya mencoba melakukannya jsonify(sample)
saya mendapatkan:
TypeError: datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) is not JSON serializable
Apa yang bisa saya lakukan sehingga sampel kamus saya dapat mengatasi kesalahan di atas?
Catatan: Meskipun mungkin tidak relevan, kamus dihasilkan dari pengambilan catatan dari mongodb
tempat ketika saya mencetak str(sample['somedate'])
, hasilnya adalah 2012-08-08 21:46:24.862000
.
Jawaban:
Diperbarui untuk 2018
Jawaban asli mengakomodasi bagaimana bidang "date" MongoDB direpresentasikan sebagai:
{"$date": 1506816000000}
Jika Anda menginginkan solusi Python generik untuk serialisasi
datetime
ke json, lihat jawaban @jjmontes untuk solusi cepat yang tidak memerlukan dependensi.Karena Anda menggunakan mongoengine (per komentar) dan pymongo adalah dependensi, pymongo memiliki utilitas bawaan untuk membantu dengan serialisasi json:
http://api.mongodb.org/python/1.10.1/api/bson/json_util.html
Contoh penggunaan (serialisasi):
Contoh penggunaan (deserialization):
Django
Django menyediakan
DjangoJSONEncoder
serializer asli yang berhubungan dengan jenis ini dengan benar.Lihat https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder
Satu perbedaan yang saya perhatikan antara
DjangoJSONEncoder
dan menggunakan customdefault
seperti ini:Apakah itu Django menghapus sedikit data:
Jadi, Anda mungkin perlu berhati-hati tentang itu dalam beberapa kasus.
sumber
Django MongoDB
. Dengan yang kemudian, Anda akan mencoba untuk tetap berada dalam ORANG Django untuk mempertahankan status agnostik backend. Tetapi kadang-kadang Anda tidak dapat melakukan apa yang Anda butuhkan dalam abstraksi, jadi Anda menjatuhkan sebuah layer. Dalam hal ini, itu sama sekali tidak terkait dengan masalah Anda karena Anda hanya menggunakan metode utilitas untuk menyertai format JSON.Tempat pembuangan JSON cepat & kotor yang memakan tanggal dan segalanya:
sumber
default
adalah fungsi yang diterapkan pada objek yang tidak bisa serial. Dalam hal inistr
, jadi itu hanya mengkonversi semua yang tidak diketahui menjadi string. Yang bagus untuk serialisasi tetapi tidak begitu bagus ketika deserializing (maka "cepat & kotor") karena segala sesuatu mungkin telah di-string-ified tanpa peringatan, misalnya fungsi atau array numpy.json.dumps({():1,type(None):2},default=str)
kenaikan gajiTypeError
, tidak bisa mengetik atau tuple.Membangun jawaban lain, solusi sederhana berdasarkan serializer spesifik yang baru saja mengkonversi
datetime.datetime
dandatetime.date
objek ke string.Seperti yang terlihat, kode hanya memeriksa untuk mengetahui apakah objek kelas
datetime.datetime
ataudatetime.date
, dan kemudian menggunakan.isoformat()
untuk menghasilkan versi serial itu, sesuai dengan format ISO 8601, YYYY-MM-DDTHH: MM: SS (yang mudah diterjemahkan oleh JavaScript ). Jika representasi serial yang lebih kompleks dicari, kode lain dapat digunakan sebagai ganti str () (lihat jawaban lain untuk pertanyaan ini sebagai contoh). Kode berakhir dengan memunculkan eksepsi, untuk menangani kasus ini disebut dengan tipe non-serializable.Fungsi json_serial ini dapat digunakan sebagai berikut:
Rincian tentang cara kerja parameter default untuk json.dumps dapat ditemukan di Bagian Penggunaan Dasar dokumentasi modul json .
sumber
01:00:00+01:00
dan02:00:00+00:00
yang tidak seharusnya sama, tergantung pada konteksnya. Mereka merujuk ke titik yang sama dalam waktu tentu saja, tetapi offset mungkin merupakan aspek yang relevan dari nilai tersebut.Saya baru saja mengalami masalah ini dan solusi saya adalah dengan subkelas
json.JSONEncoder
:Dalam panggilan Anda melakukan sesuatu seperti:
json.dumps(yourobj, cls=DateTimeEncoder)
The.isoformat()
saya dapatkan dari salah satu jawaban atas.sumber
DjangoJSONEncoder
. docs.djangoproject.com/en/dev/topics/serialization/…return super(DateTimeEncoder, self).default(o)
return super().default(o)
Ubah tanggal menjadi string
sumber
oDate = datetime.datetime.strptime(sDate, '%Y-%m-%d %H:%M:%S.%f')
. Format diperoleh dari: docs.python.org/2/library/datetime.html.now()
menggunakan waktu setempat, tanpa menunjukkan ini. Setidaknya.utcnow()
harus digunakan (dan kemudian +0000 atau Z ditambahkan)At least .utcnow() should be used
Tidak persis,datetime.now(timezone.utc)
direkomendasikan, lihat peringatan di: docs.python.org/3.8/library/… .Untuk orang lain yang tidak perlu atau ingin menggunakan pymongo library untuk ini .. Anda dapat mencapai konversi JSON datetime dengan mudah dengan potongan kecil ini:
Kemudian gunakan seperti ini:
keluaran:
sumber
millis=
ada indentasi di dalam pernyataan if? Mungkin juga lebih baik menggunakan str (obj) untuk mendapatkan format ISO yang menurut saya lebih umum.datetime.now()
mengembalikan waktu lokal (sebagai objek datetime naif) tetapi kode Anda menganggap ituobj
dalam UTC jika tidak sadar zona waktu. Gunakandatetime.utcnow()
sebagai gantinya.Inilah solusi saya:
Maka Anda dapat menggunakannya seperti itu:
sumber
isinstance(obj, datetime.datetime)
di dalam TypeError, menambahkan lebih banyak jenis untuk ditangani, dan menyelesaikan denganstr(obj)
ataurepr(obj)
. Dan semua dump Anda hanya bisa menunjuk ke kelas khusus ini.Saya memiliki aplikasi dengan masalah serupa; pendekatan saya adalah JSONisasi nilai datetime sebagai daftar 6-item (tahun, bulan, hari, jam, menit, detik); Anda bisa pergi ke mikrodetik sebagai daftar 7-item, tapi saya tidak perlu:
menghasilkan:
sumber
Solusi saya (dengan lebih sedikit verbositas, saya pikir):
Kemudian gunakan
jsondumps
sebagai gantijson.dumps
. Itu akan mencetak:Jika Anda ingin, nanti Anda dapat menambahkan kasing khusus lainnya dengan metode sederhana
default
. Contoh:sumber
Q ini berulang-ulang - cara sederhana untuk menambal modul json sedemikian rupa sehingga serialisasi akan mendukung datetime.
Daripada menggunakan serialisasi json seperti biasa - kali ini dengan datetime diserialisasi sebagai isoformat.
Menghasilkan: '{"dibuat": "2015-08-26T14: 21: 31.853855"}'
Lihat lebih detail dan beberapa kata peringatan di: StackOverflow: JSON datetime antara Python dan JavaScript
sumber
Metode json.dumps dapat menerima parameter opsional yang disebut default yang diharapkan menjadi fungsi. Setiap kali JSON mencoba mengonversi suatu nilai, ia tidak tahu bagaimana mengonversinya akan memanggil fungsi yang kami berikan. Fungsi akan menerima objek yang dimaksud, dan diharapkan untuk mengembalikan representasi objek JSON.
sumber
jika Anda menggunakan python3.7, maka solusi terbaik adalah menggunakan
datetime.isoformat()
dandatetime.fromisoformat()
; mereka bekerja dengan objek yang naif dan sadardatetime
:keluaran:
jika Anda menggunakan python3.6 atau lebih rendah, dan Anda hanya peduli dengan nilai waktu (bukan zona waktu), maka Anda dapat menggunakan
datetime.timestamp()
dandatetime.fromtimestamp()
sebagai gantinya;jika Anda menggunakan python3.6 atau di bawah, dan Anda memang peduli dengan zona waktu, maka Anda bisa mendapatkannya melalui
datetime.tzinfo
, tetapi Anda harus membuat serialisasi bidang ini sendiri; cara termudah untuk melakukan ini adalah menambahkan bidang lain_tzinfo
dalam objek bersambung;Akhirnya, berhati-hatilah dengan semua contoh dalam contoh ini;
sumber
Anda harus menggunakan
.strftime()
metode pada.datetime.now()
metode untuk menjadikannya sebagai metode serializable .Ini sebuah contoh:
Keluaran:
sumber
Berikut adalah solusi sederhana untuk mengatasi masalah "datetime not JSON serializable".
Output: -> {"date": "2015-12-16T04: 48: 20.024609"}
sumber
Anda harus menyediakan kelas pembuat enkode khusus dengan
cls
parameterjson.dumps
. Mengutip dari dokumen :Ini menggunakan bilangan kompleks sebagai contoh, tetapi Anda dapat dengan mudah membuat kelas untuk menyandikan tanggal (kecuali saya pikir JSON sedikit kabur tentang tanggal)
sumber
Cara paling sederhana untuk melakukan ini adalah mengubah bagian dict yang ada dalam format datetime menjadi isoformat. Nilai itu akan secara efektif menjadi string di isoformat yang json baik-baik saja dengan.
sumber
Sebenarnya itu cukup sederhana. Jika Anda harus sering membuat serial tanggal, maka buatlah itu sebagai string. Anda dapat dengan mudah mengubahnya kembali sebagai objek datetime jika diperlukan.
Jika Anda perlu bekerja sebagian besar sebagai objek datetime, lalu konversikan sebagai string sebelum membuat cerita bersambung.
Seperti yang Anda lihat, hasilnya sama dalam kedua kasus. Hanya jenisnya yang berbeda.
sumber
Jika Anda menggunakan hasil dalam tampilan pastikan untuk mengembalikan respons yang tepat. Menurut API, jsonify melakukan hal berikut:
Untuk meniru perilaku ini dengan json.dumps Anda harus menambahkan beberapa baris kode tambahan.
Anda juga harus mengembalikan dict untuk sepenuhnya mereplikasi respons jsonify. Jadi, seluruh file akan terlihat seperti ini
sumber
pymongo
.Coba yang ini dengan contoh untuk menguraikannya:
sumber
Solusi saya ...
Ok, sekarang beberapa tes.
sumber
Berikut ini adalah solusi lengkap saya untuk mengubah datetime ke JSON dan kembali ..
Keluaran
File JSON
Ini memungkinkan saya untuk mengimpor dan mengekspor objek string, int, float dan datetime. Seharusnya tidak sulit untuk memperluas untuk jenis lain.
sumber
TypeError: 'str' does not support the buffer interface
. Itu karena'wb'
mode terbuka, seharusnya'w'
. Itu juga berhembus deserialization ketika kita memiliki data yang mirip dengan tanggal seperti'0000891618-05-000338'
tetapi tidak cocok dengan pola.Konversikan
date
kestring
sumber
Secara umum ada beberapa cara untuk membuat serial berita, seperti:
Jika Anda setuju dengan cara terakhir, paket json_tricks menangani tanggal, waktu, dan waktu termasuk zona waktu.
pemberian yang mana:
Jadi yang perlu Anda lakukan adalah
dan kemudian impor dari
json_tricks
bukanjson
.Keuntungan dari tidak menyimpannya sebagai string tunggal, int atau float muncul ketika decoding: jika Anda menemukan hanya string atau terutama int atau float, Anda perlu mengetahui sesuatu tentang data untuk mengetahui apakah itu merupakan waktu. Sebagai dikt, Anda dapat menyimpan metadata sehingga dapat diterjemahkan secara otomatis, yang
json_tricks
memang cocok untuk Anda. Ini juga mudah diedit untuk manusia.Penafian: itu dibuat oleh saya. Karena saya punya masalah yang sama.
sumber
Saya mendapat pesan kesalahan yang sama saat menulis dekorator bersambung di dalam Kelas dengan sqlalchemy. Jadi alih-alih:
Saya hanya meminjam ide jgbarah tentang menggunakan isoformat () dan menambahkan nilai asli dengan isoformat (), sehingga sekarang terlihat seperti:
sumber
Perbaikan cepat jika Anda ingin memformat sendiri
sumber
Jika Anda berada di kedua sisi komunikasi Anda dapat menggunakan fungsi repr () dan eval () bersama dengan json.
Anda tidak boleh mengimpor datetime sebagai
karena eval akan mengeluh. Atau Anda bisa melewatkan datetime sebagai parameter untuk eval. Bagaimanapun ini harus berhasil.
sumber
Saya pernah mengalami masalah yang sama ketika mengeksternalisasi objek model Django untuk dibuang sebagai JSON. Inilah cara Anda bisa menyelesaikannya.
sumber
Penggunaan utilitas di atas:
sumber
Superjson perpustakaan ini dapat melakukannya. Dan Anda dapat dengan mudah mengubahsuaikan serializer json untuk Objek Python Anda sendiri dengan mengikuti instruksi ini https://superjson.readthedocs.io/index.html#extend .
Konsep umum adalah:
kode Anda perlu menemukan metode serialisasi / deserialisasi yang tepat berdasarkan objek python. Biasanya, nama kelas lengkap adalah pengidentifikasi yang baik.
Dan kemudian metode ser / deser Anda harus dapat mengubah objek Anda menjadi objek serialson Json biasa, kombinasi tipe python generik, dict, list, string, int, float. Dan terapkan metode deser Anda secara terbalik.
sumber
Saya mungkin tidak 100% benar tetapi, ini adalah cara sederhana untuk membuat cerita bersambung
sumber