Django ORM: values() 메서드 사용 시 get_field_display() 동작하지 않는 문제

Kangjik Kim·2025년 3월 30일
0

문제 상황

Django에서 모델의 choices 필드를 사용할 때, get_[field]_display() 메서드를 통해 쉽게 표시값을 가져올 수 있습니다. 하지만 .values()를 사용하면 이 메서드가 동작하지 않는 상황이 발생합니다.

예를 들어, 다음과 같은 모델이 있다고 가정해보겠습니다:

class Notice(models.Model):
    CATEGORY_CHOICES = (
        ('NOTICE', '공지'),
        ('EVENT', '이벤트'),
        ('NEWS', '뉴스'),
    )
    category = models.CharField(max_length=10, choices=CATEGORY_CHOICES)

일반적으로는 다음과 같이 사용할 수 있습니다:

notice = Notice.objects.first()
print(notice.get_category_display())  # '공지' 출력

하지만 .values()를 사용하면:

notice = Notice.objects.values('category').first()
# notice.get_category_display()  # AttributeError 발생!

원인

.values()는 모델 인스턴스가 아닌 딕셔너리를 반환합니다. 따라서 모델 인스턴스의 메서드인 get_[field]_display()를 사용할 수 없게 됩니다.

해결 방법

1. values() 사용하지 않기

가장 간단한 방법은 .values()를 사용하지 않고 모델 인스턴스를 직접 사용하는 것입니다:

notices = Notice.objects.all()
for notice in notices:
    print(notice.get_category_display())

2. annotate()로 display 필드 추가하기

성능상의 이유로 .values()가 필요한 경우, annotate()를 사용하여 display 값을 직접 추가할 수 있습니다:

from django.db.models import Case, When, Value, CharField

notices = Notice.objects.annotate(
    category_display=Case(
        *[When(category=k, then=Value(v)) for k, v in Notice.CATEGORY_CHOICES],
        output_field=CharField(),
    )
).values('category', 'category_display')

각 방법의 장단점

values()를 사용하지 않는 방법

장점:

  • 코드가 간단하고 직관적
  • 모델의 모든 기능을 사용 가능

단점:

  • 모델 인스턴스 전체를 메모리에 로드
  • 대량의 데이터 처리 시 성능 저하 가능성

annotate()를 사용하는 방법

장점:

  • 필요한 필드만 선택적으로 가져올 수 있음
  • 데이터베이스 레벨에서 처리되어 성능상 이점

단점:

  • 코드가 다소 복잡
  • choices 정의가 변경될 경우 annotate 로직도 수정 필요

결론

.values()의 사용은 성능 최적화에 도움이 될 수 있지만, get_[field]_display()와 같은 모델 메서드를 사용할 수 없다는 제한이 있습니다. 프로젝트의 요구사항과 성능 특성을 고려하여 적절한 방법을 선택하는 것이 중요합니다.

0개의 댓글