Ada banyak cara untuk mengkonversi instance ke kamus, dengan berbagai tingkat penanganan kasus sudut dan kedekatan dengan hasil yang diinginkan.
1. instance.__dict__
instance.__dict__
yang kembali
{'_foreign_key_cache': <OtherModel: OtherModel object>,
'_state': <django.db.models.base.ModelState at 0x7ff0993f6908>,
'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key_id': 2,
'id': 1,
'normal_value': 1,
'readonly_value': 2}
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
from django.forms.models import model_to_dict
model_to_dict(instance)
yang kembali
{'foreign_key': 2,
'id': 1,
'many_to_many': [<OtherModel: OtherModel object>],
'normal_value': 1}
Ini adalah satu-satunya yang ada many_to_many
, tetapi tidak memiliki bidang yang tidak dapat diedit.
3. model_to_dict(..., fields=...)
from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])
yang kembali
{'foreign_key': 2, 'id': 1, 'normal_value': 1}
Ini benar-benar lebih buruk daripada model_to_dict
doa standar .
4. query_set.values()
SomeModel.objects.filter(id=instance.id).values()[0]
yang kembali
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key_id': 2,
'id': 1,
'normal_value': 1,
'readonly_value': 2}
Ini adalah output yang sama seperti instance.__dict__
tetapi tanpa bidang tambahan.
foreign_key_id
masih salah dan many_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:
from itertools import chain
def to_dict(instance):
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields):
data[f.name] = f.value_from_object(instance)
for f in opts.many_to_many:
data[f.name] = [i.id for i in f.value_from_object(instance)]
return data
Meskipun ini adalah opsi yang paling rumit, panggilan to_dict(instance)
memberi kami hasil yang diinginkan:
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
6. Gunakan Serializers
ModelSerialzer Django Rest Framework memungkinkan Anda membuat serializer secara otomatis dari suatu model.
from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = "__all__"
SomeModelSerializer(instance).data
kembali
{'auto_now_add': '2018-12-20T21:34:29.494827Z',
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
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:
from django.db import models
from itertools import chain
class PrintableModel(models.Model):
def __repr__(self):
return str(self.to_dict())
def to_dict(instance):
opts = instance._meta
data = {}
for f in chain(opts.concrete_fields, opts.private_fields):
data[f.name] = f.value_from_object(instance)
for f in opts.many_to_many:
data[f.name] = [i.id for i in f.value_from_object(instance)]
return data
class Meta:
abstract = True
Jadi, misalnya, jika kita mendefinisikan model kita seperti itu:
class OtherModel(PrintableModel): pass
class SomeModel(PrintableModel):
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")
Panggilan SomeModel.objects.first()
sekarang memberikan hasil seperti ini:
{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
'foreign_key': 2,
'id': 1,
'many_to_many': [2],
'normal_value': 1,
'readonly_value': 2}
to_dict
dan menanganinya seperti yang Anda inginkan.