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}


+ Recent posts