Bagaimana seseorang mengonversi objek Model Django ke dict dengan semua bidangnya? Semua idealnya menyertakan kunci dan bidang asing dengan editable=False
.
Biarkan saya uraikan. Katakanlah saya memiliki model Django seperti berikut:
from django.db import models
class OtherModel(models.Model): pass
class SomeModel(models.Model):
normal_value = models.IntegerField()
readonly_value = models.IntegerField(editable=False)
auto_now_add = models.DateTimeField(auto_now_add=True)
foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")
Di terminal, saya telah melakukan hal berikut:
other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()
Saya ingin mengonversi ini ke kamus berikut:
{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
'foreign_key': 1,
'id': 1,
'many_to_many': [1],
'normal_value': 1,
'readonly_value': 2}
Pertanyaan dengan jawaban yang tidak memuaskan:
Django: Mengubah seluruh set objek Model menjadi satu kamus
Bagaimana saya bisa mengubah objek Model Django menjadi kamus dan masih memiliki kunci asing mereka?
to_dict
dan menanganinya seperti yang Anda inginkan._meta
definisi model untuk menemukan bidang yang terkait dengan model dan mengambil nilai-nilai mereka pada instance.Jawaban:
Ada banyak cara untuk mengkonversi instance ke kamus, dengan berbagai tingkat penanganan kasus sudut dan kedekatan dengan hasil yang diinginkan.
1.
instance.__dict__
yang kembali
Sejauh ini, ini adalah yang paling sederhana, tetapi tidak ada
many_to_many
,foreign_key
salah nama, dan ada dua hal tambahan yang tidak diinginkan di dalamnya.2.
model_to_dict
yang kembali
Ini adalah satu-satunya yang ada
many_to_many
, tetapi tidak memiliki bidang yang tidak dapat diedit.3.
model_to_dict(..., fields=...)
yang kembali
Ini benar-benar lebih buruk daripada
model_to_dict
doa standar .4.
query_set.values()
yang kembali
Ini adalah output yang sama seperti
instance.__dict__
tetapi tanpa bidang tambahan.foreign_key_id
masih salah danmany_to_many
masih hilang.5. Fungsi Kustom
Kode untuk Django
model_to_dict
memiliki sebagian besar jawabannya. Itu secara eksplisit menghapus bidang yang tidak dapat diedit, jadi menghapus centang itu dan mendapatkan id kunci asing untuk banyak ke banyak bidang menghasilkan kode berikut yang berperilaku seperti yang diinginkan:Meskipun ini adalah opsi yang paling rumit, panggilan
to_dict(instance)
memberi kami hasil yang diinginkan:6. Gunakan Serializers
ModelSerialzer Django Rest Framework memungkinkan Anda membuat serializer secara otomatis dari suatu model.
kembali
Ini hampir sebagus fungsi kustom, tetapi auto_now_add adalah string, bukan objek datetime.
Putaran Bonus: pencetakan model yang lebih baik
Jika Anda menginginkan model Django yang memiliki tampilan baris perintah python yang lebih baik, mintalah kelas anak Anda model berikut:
Jadi, misalnya, jika kita mendefinisikan model kita seperti itu:
Panggilan
SomeModel.objects.first()
sekarang memberikan hasil seperti ini:sumber
isinstance
tes dalam solusi # 5 (dan bonus) menjadiif f.many_to_many
.model_to_dict
, yang menggunakanisinstance
. Saya tidak yakin mengapa mereka membuat pilihan ini, tetapi mungkin ada alasan bagus untuk itu (sepertimany_to_many
properti yang diperkenalkan dalam versi yang lebih baru)@property
bidang?Saya menemukan solusi yang rapi untuk mendapatkan hasil:
Misalkan Anda memiliki objek model
o
:Panggil saja:
sumber
Solusi Zags sangat bagus!
Saya akan menambahkan, bagaimanapun, suatu kondisi untuk datefields agar JSON friendly.
Putaran Bonus
Jika Anda menginginkan model Django yang memiliki tampilan baris perintah python yang lebih baik, mintalah kelas anak model Anda sebagai berikut:
Jadi, misalnya, jika kita mendefinisikan model kita seperti itu:
Panggilan
SomeModel.objects.first()
sekarang memberikan hasil seperti ini:sumber
Cara paling sederhana,
Jika kueri Anda Model.Objects.get ():
get () akan mengembalikan satu instance sehingga Anda dapat mengarahkan penggunaan
__dict__
dari instance Andamodel_dict =
Model.Objects.get().__dict__
untuk filter () / semua ():
all () / filter () akan mengembalikan daftar instance sehingga Anda dapat menggunakan
values()
untuk mendapatkan daftar objek.model_values = Model.Objects.all (). values ()
sumber
hanya
vars(obj)
, ini akan menyatakan seluruh nilai objekAnda dapat menambahkan ini juga
sumber
Memperbarui
Jawaban teragregasi yang lebih baru yang dikirim oleh @zags lebih lengkap dan elegan daripada jawaban saya. Silakan merujuk ke jawaban itu sebagai gantinya.
Asli
Jika Anda ingin mendefinisikan metode to_dict Anda sendiri seperti yang disarankan @karthiker, maka itu hanya akan memunculkan masalah ini menjadi masalah kumpulan.
Kita perlu menghapus kunci asing yang salah label dari otherDict .
Untuk melakukan ini, kita dapat menggunakan loop yang membuat kamus baru yang memiliki setiap item kecuali yang bergaris bawah di dalamnya. Atau, untuk menghemat waktu, kita bisa menambahkannya ke dikt asli karena kamus hanya diset di bawah tenda.
Jadi kita dibiarkan dengan dikt berikut :
Dan Anda hanya mengembalikannya.
Pada sisi negatifnya, Anda tidak dapat menggunakan garis bawah pada nama bidang Anda yang dapat diedit = salah. Pada terbalik, ini akan berfungsi untuk set bidang mana pun di mana bidang buatan pengguna tidak mengandung garis bawah.
Ini bukan cara terbaik untuk melakukan ini, tetapi ini bisa berfungsi sebagai solusi sementara sampai metode yang lebih langsung ditemukan.
Untuk contoh di bawah ini, dict akan dibentuk berdasarkan model_to_dict dan otherDict akan dibentuk oleh metode nilai filter. Saya akan melakukan ini dengan model itu sendiri, tetapi saya tidak bisa mendapatkan mesin saya untuk menerima Model lain.
Itu seharusnya menempatkan Anda pada kasarnya jawaban atas pertanyaan Anda, saya harap.
sumber
re
untuk di sini. Jika ingin menyaring kunci dengan garis bawah di dalamnya, ini bukan kode yang benar atau perilaku yang benar.re.match("_", "reference1_id")
kembaliNone
dan kolom yang sah dalam database mungkin memiliki garis bawah dalam nama mereka.editable=false
bidangnya. Saya hanya mencoba memberikan sesuatu yang mungkin dapat Anda kerjakan sampai solusi yang lebih kanon dapat disampaikan."_" in string
daripadare
dalam kasus itu.in
sebagai gantinyare
.Banyak solusi menarik di sini. Solusi saya adalah menambahkan metode as_dict ke model saya dengan pemahaman dict.
Sebagai bonus, solusi ini dipasangkan dengan pemahaman daftar atas permintaan membuat solusi yang bagus jika Anda ingin mengekspor model Anda ke perpustakaan lain. Misalnya, membuang model Anda ke dalam kerangka data panda:
sumber
(tidak bermaksud berkomentar)
Ok, itu tidak benar-benar tergantung pada jenis dengan cara itu. Saya mungkin salah mengerti pertanyaan asli di sini, jadi maafkan saya jika itu masalahnya. Jika Anda membuat serliazers.py maka di sana Anda membuat kelas yang memiliki kelas meta.
Kemudian ketika Anda mendapatkan data di kelas tampilan Anda bisa:
Itulah yang saya miliki di berbagai tempat dan mengembalikan JSON yang bagus melalui JSONRenderer.
Seperti yang saya katakan ini adalah milik DjangoRestFramework, jadi ada baiknya melihat ke dalamnya.
sumber
Cara yang lebih mudah adalah dengan menggunakan
pprint
, yang ada di basis PythonIni memberikan output yang terlihat mirip dengan
json.dumps(..., indent = 4)
tetapi dengan benar menangani tipe data aneh yang mungkin tertanam dalam contoh model Anda, sepertiModelState
danUUID
, dll.Diuji dengan Python 3.7
sumber
Mungkin ini membantu Anda. Mungkin ini tidak banyak hubungan rahasia ke banyak, tetapi sangat berguna ketika Anda ingin mengirim model Anda dalam format json.
sumber
Solusi terbaik yang pernah Anda lihat.
Ubah instance django.db.models.Model dan semua bidang fungsi ForeignKey, ManyToManyField, dan @Property yang terkait menjadi dict.
https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52
sumber
Jawaban dari @zags komprehensif dan harus cukup
tetapi metode # 5 (yang merupakan IMO terbaik) melempar kesalahan jadi saya meningkatkan fungsi helper.Sebagai OP yang diminta untuk mengubah
many_to_many
bidang menjadi daftar kunci utama daripada daftar objek, saya meningkatkan fungsi sehingga nilai kembali sekarang JSON serializable - dengan mengubahdatetime
objek menjadistr
danmany_to_many
objek ke daftar id.sumber
concrete_fields
danm2m_fields
terlihat identik, jadi dengan asumsim2m_fields
loop memiliki implementasi yang salah di sini.AttributeError: 'list' object has no attribute 'values_list'
saya tidak bisa menemukan alasan di baliknya. Saya menggunakan Django 2.1.1field.value_from_object
dan sebagai hasilnya, darimodel_to_dict
. Saya telah memperbarui bagian 5 dari jawaban saya untuk mencerminkan hal ini.