-
[Django] model object 에서 dict 타입으로 변환하기언어/파이썬 & 장고 2017. 2. 1. 20:23
django model object to dict!
모델객체에서 dict타입으로의 변환은 여러 방법이 있습니다. 참고로 Django ORM에서 model 객체로 결과가 나오는 것은 get()과 같은 형식이여야 합니다. filter()처럼 QuerySet으로 나오는 형태는 에러가 날 수 있습니다.
test case
모델
from django.db import models class OtherModel(models.Model): pass class SomeModel(models.Model): value = models.IntegerField() value2 = models.IntegerField(editable=False) created = models.DateTimeField(auto_now_add=True) reference1 = models.ForeignKey(OtherModel, related_name="ref1") reference2 = models.ManyToManyField(OtherModel, related_name="ref2")
데이터
other_model = OtherModel() other_model.save() instance = SomeModel() instance.value = 1 instance.value2 = 2 instance.reference1 = other_model instance.save() instance.reference2.add(other_model) instance.save()
출력되길 원하는 포맷
{'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1, 'value2': 2}
위와같은 형태로 모델과 데이터가 존재한다 했을 때, instance 객체를 dict타입으로 변환하는 방법을 아래에서 설명합니다.
instance.__dict__
instance.__dict__ # 결과 {'_reference1_cache': <OtherModel: OtherModel object>, '_state': <django.db.models.base.ModelState at 0x1f63310>, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51, 844795, tzinfo=<UTC>), 'id': 1L, 'reference1_id': 1L, 'value': 1, 'value2': 2}
이 방법은 간단하지만 사용자가 원하는 key값으로만 나오는 것이 아니며 데이터가 추가되어서 나오기도 합니다. 위를 보면 reference2의 key가 빠졌습니다. 또한 reference1은 네이밍이 잘못 되었으며 두 개의 데이터가 추가되었습니다.
model_to_dict
from django.forms.models import model_to_dict model_to_dict(instance) # 결과 {u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1}
위 방법은 대개 모델에 사용자가 직접 입력한 데이터만 출력하는데에 사용하면 적합합니다. 하지만 예제 모델에는 autoField가 존재하여 자동생성된 필드의 값은 출력되지 않은 것을 확인 할 수 있습니다.
model_to_dict with fields
from django.forms.models import model_to_dict model_to_dict(instance, fields=[field.name for field in instance._meta.fields]) # 결과 {u'id': 1L, 'reference1': 1L, 'value': 1}
이 방법은 위의 model_to_dict의 표준방법보다도 못한 방법입니다.
query_set.values()
SomeModel.objects.filter(id=instance.id).values()[0] # 결과 {'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>), u'id': 1L, 'reference1_id': 1L, 'value': 1L, 'value2': 2L}
이것은 instance.__dict__와 같은 결과이지만 추가적인 필드는 존재하지 않습니다.
Custom Function
장고의 model_to_dict 모듈에 대부분 답을 가지고 있습니다. 명시적으로 편집할 수 없는 필드들은 제거가 됩니다. 따라서 해당 검사(편집할 수 없는 필드를 삭제하는 부분)를 제거하면 원하는대로 작동하는 다음 코드가 생성됩니다.
from django.db.models.fields.related import ManyToManyField def to_dict(instance): opts = instance._meta data = {} for f in opts.concrete_fields + opts.many_to_many: if isinstance(f, ManyToManyField): if instance.pk is None: data[f.name] = [] else: data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True)) else: data[f.name] = f.value_from_object(instance) return data
위 작업은 복잡하지만 위의 함수 to_dict(instance)를 호출하면 원하는 답을 받을 수 있습니다.
{'created': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>), u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1, 'value2': 2}