ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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}


    댓글