Django memiliki beberapa serialisasi otomatis yang baik dari model ORM yang dikembalikan dari format DB ke JSON.
Bagaimana cara membuat serialisasi hasil query SQLAlchemy ke format JSON?
Saya mencoba jsonpickle.encode
tetapi itu mengkodekan objek permintaan itu sendiri. Saya mencoba json.dumps(items)
tetapi kembali
TypeError: <Product('3', 'some name', 'some desc')> is not JSON serializable
Apakah sangat sulit untuk membuat serial objek SQLAlchemy ORM ke JSON / XML? Apakah tidak ada serializer default untuk itu? Ini tugas yang sangat umum untuk membuat serialisasi hasil permintaan ORM saat ini.
Yang saya butuhkan hanyalah mengembalikan JSON atau representasi data XML dari hasil kueri SQLAlchemy.
Hasil query objek SQLAlchemy dalam format JSON / XML diperlukan untuk digunakan dalam javascript datagird (JQGrid http://www.trirand.com/blog/ )
sumber
Jawaban:
Implementasi yang datar
Anda dapat menggunakan sesuatu seperti ini:
lalu konversi ke JSON menggunakan:
Ini akan mengabaikan bidang yang tidak dapat disandikan (atur ke 'Tidak Ada').
Itu tidak memperluas hubungan secara otomatis (karena ini bisa mengarah pada referensi-sendiri, dan berulang selamanya).
Implementasi rekursif, non-sirkuler
Namun, jika Anda lebih suka mengulang selamanya, Anda dapat menggunakan:
Dan kemudian menyandikan objek menggunakan:
Ini akan menyandikan semua anak, dan semua anak mereka, dan semua anak mereka ... Berpotensi menyandikan seluruh basis data Anda, pada dasarnya. Ketika mencapai sesuatu yang disandikan sebelumnya, itu akan menyandikannya sebagai 'Tidak Ada'.
Implementasi rekursif, mungkin melingkar, selektif
Alternatif lain, mungkin lebih baik, adalah untuk dapat menentukan bidang yang ingin Anda kembangkan:
Anda sekarang dapat menyebutnya dengan:
Untuk hanya memperluas bidang SQLAlchemy yang disebut 'parent', misalnya.
sumber
online_order
danaddress
, keduanya memiliki hubungan denganuser
, tetapionline_order
juga memiliki hubungan denganaddress
. Jika saya ingin membuat serial semua ini, saya harus memasukkannyaaddress
dalamfields_to_expand
, tapi saya tidak ingin serialisasi secara berlebihanaddress
karena hubungannya dengan keduanyauser
danonline_order
.for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
sehingga terbacafor field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata' and not x.startswith('query')]:
. Ingatlah bahwa solusi ini akan mencegah Anda dari memiliki properti / hubungan dengan nama 'permintaan'Anda bisa menampilkan objek Anda sebagai kamus:
Dan kemudian Anda gunakan
User.as_dict()
untuk membuat serial objek Anda.Seperti dijelaskan dalam Mengkonversi objek baris sqlalchemy ke python dict
sumber
JSONEncoder
objek. Anda bisa subklas untuk mendefinisikan encoder Anda sendiri untuk beberapa objek, termasuk datetime. Perhatikan bahwaFlask
, misalnya, mendukung penyandian datetime di JSON di luar kotak (dengan versi terbaru).return {c.name: unicode(getattr(self, c.name)) for c in self.__table__.columns}
Anda dapat mengonversi RowProxy ke dict seperti ini:
Kemudian serialkan ke JSON (Anda harus menentukan encoder untuk hal-hal seperti
datetime
nilai) Tidak sulit jika Anda hanya ingin satu catatan (dan bukan hierarki penuh catatan terkait).sumber
Saya sarankan menggunakan marshmallow . Ini memungkinkan Anda untuk membuat serializers untuk mewakili contoh model Anda dengan dukungan untuk relasi dan objek bersarang.
Berikut adalah contoh terpotong dari dokumen mereka. Mengambil model ORM,
Author
:Skema marshmallow untuk kelas itu dibangun seperti ini:
... dan digunakan seperti ini:
... akan menghasilkan output seperti ini:
Lihat Contoh lengkap Labu-SQLAlchemy mereka .
Perpustakaan yang disebut
marshmallow-sqlalchemy
secara khusus mengintegrasikan SQLAlchemy dan marshmallow. Di perpustakaan itu, skema untukAuthor
model yang dijelaskan di atas terlihat seperti ini:Integrasi ini memungkinkan jenis bidang disimpulkan dari
Column
jenis SQLAlchemy .marshmallow-sqlalchemy di sini.
sumber
Python 3.7+ dan Flask 1.1+ dapat menggunakan paket dataclasses bawaan
The
/users/
rute sekarang akan kembali daftar pengguna.Membuat serialisasi model terkait secara otomatis
Tanggapan dari
jsonify(account)
akan seperti ini.Timpa JSON Encoder default
sumber
data = request.json['user']; user = User(**data)
id: int = Column
akan bekerja, tetapiid = Column
tidak akan, sepertinya ANDA HARUS mendeklarasikan pengetikan statis untuk json untuk membuat serial bidang, jika tidak, Anda mendapatkan{}
objek kosong .pipenv install dataclasses
. Dan itu akan bekerja dengan baik.Paket Flask-JsonTools memiliki implementasi kelas JsonSerializableBase Base untuk model Anda.
Pemakaian:
Sekarang
User
model ini dapat diserialkan secara ajaib.Jika kerangka kerja Anda bukan Flask, Anda bisa mengambil kode
sumber
import flask.ext.whatever
tidak lagi didukung di Flask 1.0.Untuk alasan keamanan Anda tidak boleh mengembalikan semua bidang model. Saya lebih suka memilihnya secara selektif.
Pengkodean json Flask sekarang mendukung UUID, datetime dan hubungan (dan ditambahkan
query
danquery_class
untukdb.Model
kelas flask_sqlalchemy ). Saya telah memperbarui encoder sebagai berikut:Dengan ini saya secara opsional dapat menambahkan
__json__
properti yang mengembalikan daftar bidang yang ingin saya encode:Saya menambahkan @jsonapi ke tampilan saya, mengembalikan daftar hasil dan kemudian output saya adalah sebagai berikut:
sumber
@jsonapi
ke@app.route
dalam views.py dll), tapi saya menyukai kesederhanaan itu. Saya pikir itu adalah Flask yang murah, tapi tidak ada tanggal jadi saya menambahkannya sendiri ke json_encoder.py :value=...
^if isinstance(value, date):
^data[field] = datetime.combine(value, time.min).isoformat()
^else:
^try:...
Anda dapat menggunakan introspeksi SqlAlchemy karena ini:
Dapatkan inspirasi dari jawaban di sini: Konversikan objek baris sqlalchemy ke python dict
sumber
Penjelasan lebih rinci. Dalam model Anda, tambahkan:
Ini
str()
untuk python 3 jadi jika menggunakan python 2 gunakanunicode()
. Seharusnya membantu deserialize tanggal. Anda dapat menghapusnya jika tidak berurusan dengan itu.Anda sekarang dapat meminta basis data seperti ini
First()
diperlukan untuk menghindari kesalahan aneh.as_dict()
sekarang akan deserialize hasilnya. Setelah deserialisasi, siap untuk diubah menjadi jsonsumber
Ini tidak begitu lurus ke depan. Saya menulis beberapa kode untuk melakukan ini. Saya masih mengerjakannya, dan menggunakan kerangka kerja MochiKit. Ini pada dasarnya menerjemahkan objek majemuk antara Python dan Javascript menggunakan proxy dan konverter JSON terdaftar.
Sisi peramban untuk objek basis data adalah db.js. Diperlukan sumber proxy Python dasar di proxy.js .
Di sisi Python ada modul proxy dasar . Kemudian akhirnya encoder objek SqlAlchemy di webserver.py . Ini juga tergantung pada ekstraktor metadata yang ditemukan dalam file models.py .
sumber
Sementara pertanyaan awal kembali beberapa waktu, jumlah jawaban di sini (dan pengalaman saya sendiri) menunjukkan bahwa ini adalah pertanyaan yang tidak sepele dengan banyak pendekatan berbeda dari kompleksitas yang berbeda dengan pengorbanan yang berbeda.
Itu sebabnya saya membangun perpustakaan SQLAthanor yang memperluas ORM deklaratif SQLAlchemy dengan dukungan serialisasi / de-serialisasi yang dapat dikonfigurasi yang mungkin ingin Anda lihat.
Perpustakaan mendukung:
dict
password
, tetapi tidak pernah menyertakan yang keluar )Anda dapat melihat dokumen komprehensif (saya harap!) Di sini: https://sqlathanor.readthedocs.io/en/latest
Semoga ini membantu!
sumber
Serialisasi dan deserialisasi kustom.
"from_json" (metode kelas) membangun objek Model berdasarkan data json.
"deserialize" hanya bisa dipanggil pada contoh, dan menggabungkan semua data dari json ke dalam Contoh model.
"serialize" - serialisasi rekursif
Properti __write_only__ diperlukan untuk mendefinisikan properti hanya tulis ("password_hash" misalnya).
sumber
Berikut ini adalah solusi yang memungkinkan Anda memilih hubungan yang ingin Anda sertakan dalam output Anda sedalam yang Anda inginkan. CATATAN: Ini adalah penulisan ulang yang lengkap dengan mengambil dict / str sebagai arg dan bukan daftar. memperbaiki beberapa hal ..
jadi untuk contoh menggunakan orang / keluarga / rumah / kamar ... mengubahnya menjadi json yang Anda butuhkan
sumber
Saya pikir saya akan bermain golf kode kecil dengan yang ini.
FYI: Saya menggunakan automap_base karena kami memiliki skema yang dirancang secara terpisah sesuai dengan persyaratan bisnis. Saya baru saja mulai menggunakan SQLAlchemy hari ini tetapi dokumentasi menyatakan bahwa automap_base adalah ekstensi untuk declarative_base yang tampaknya menjadi paradigma khas dalam ORM SQLAlchemy jadi saya percaya ini harus bekerja.
Itu tidak terbiasa dengan mengikuti kunci asing per solusi Tjorriemorrie , tetapi hanya mencocokkan kolom dengan nilai dan menangani tipe Python dengan str () - ing nilai kolom. Nilai-nilai kami terdiri dari Python datetime.time dan desimal. Hasil tipe kelas desimal sehingga menyelesaikan pekerjaan.
Semoga ini bisa membantu orang yang lewat!
sumber
Saya tahu ini posting yang cukup lama. Saya mengambil solusi yang diberikan oleh @SashaB dan dimodifikasi sesuai kebutuhan saya.
Saya menambahkan hal-hal berikut ke dalamnya:
Kode saya adalah sebagai berikut:
Semoga ini bisa membantu seseorang!
sumber
Gunakan serializer bawaan di SQLAlchemy:
Jika Anda mentransfer objek di antara sesi, ingatlah untuk melepaskan objek dari sesi saat ini menggunakan
session.expunge(obj)
. Untuk melampirkannya lagi, lakukan sajasession.add(obj)
.sumber
kode berikut akan membuat serial hasil sqlalchemy ke json.
Menyenangkan,
sumber
AlchemyEncoder luar biasa tetapi terkadang gagal dengan nilai Desimal. Berikut ini adalah pembuat enkode yang disempurnakan yang memecahkan masalah desimal -
sumber
Saat menggunakan sqlalchemy untuk terhubung ke db, saya ini adalah solusi sederhana yang sangat dapat dikonfigurasi. Gunakan panda.
sumber
sumber
Di bawah Flask, ini berfungsi dan menangani bidang datatime, mengubah bidang tipe
'time': datetime.datetime(2018, 3, 22, 15, 40)
menjadi"time": "2018-03-22 15:40:00"
:sumber
Serial serializer bawaan dengan utf-8 tidak dapat mendekode byte awal yang tidak valid untuk beberapa input. Sebaliknya, saya pergi dengan:
sumber
Mungkin Anda bisa menggunakan kelas seperti ini
Dengan itu semua objek memiliki
to_dict
metodesumber
Saat menggunakan beberapa sql mentah dan objek tidak terdefinisi, menggunakan
cursor.description
muncul untuk mendapatkan apa yang saya cari:sumber
Kamus yang saya gunakan (terlalu banyak?):
Berjalan dengan flask (termasuk jsonify) dan flask_sqlalchemy untuk mencetak output sebagai JSON.
Panggil fungsi dengan jsonify (serialize ()).
Bekerja dengan semua pertanyaan SQLAlchemy yang telah saya coba sejauh ini (menjalankan SQLite3)
sumber