본문 바로가기
Django

Django TextChoices로 상수 관리하기

by dhleeone 2025. 1. 5.

Enum

Python에서 열거형 상수를 관리할 때 Enum 클래스를 자주 사용합니다. 

from enum import Enum

class StatusEnum(Enum):
    PENDING = "Pending"
    APPROVED = "Approved"
    REJECTED = "Rejected"

 

Enum을 사용했을 때의 장점

코드 가독성 향상: 상수를 그룹화하여 일관된 코드를 작성

구조적 관리 가능: 열거형을 통해 상수로 관리하므로 코드의 유지보수성을 높임

 

하지만 Enum 클래스에는 몇 가지 단점이 있습니다.

 

 

1. value 속성을 통해 값에 접근해야 함

Python Enum에서 열거형 멤버는 객체로 동작하며 내부적으로 이름(name)과 값(value)을 속성으로 가지고 있습니다.

따라서 실제 값에 접근하려면 .value 속성을 사용해야 합니다.

 

아래와 같이 문자열과 열거형 멤버를 비교할 때 .value를 명시하지 않으면, 실제 값이 아닌 객체 자체를 비교하게 되어 올바른 결과를 얻지 못할 수 있습니다.

이러한 특성으로 value 누락 시 오류를 발생시키곤 합니다.

(이를 방지하기 위해 python 3.11 이후부터 Enum 대신 StrEnum을 사용할 수 있습니다.)

"Pending" == StatusEnum.PENDING
# False

"Pending" == StatusEnum.PENDING.value
# True

 

2. 모든 Enum 멤버의 값(value) 또는 이름(name)을 가져오기 어렵다

Enum 클래스에는 모든 멤버의 값이나 이름을 한 번에 가져오는 내장 메서드가 없습니다.

따라서 아래 예시와 같이 일일히 value들을 선언해줘야하는 번거로움이 존재하고 멤버가 많을수록 코드 가독성이 낮아지게 됩니다.

 

if status not in (StatusEnum.PENDING, StatusEnum.APPROVED, StatusEnum.REJECTED):
	print("Invalid status.")

 

3. django 모델 필드와 호환되지 않음

django 모델 CharField의 choices 옵션으로 Enum 클래스를 지정할 수 없기 때문에 django에서 사용 시 한계가 존재합니다.

 

TextChoices

django는 Enum의 한계를 극복하기 위해 TextChoices 클래스를 제공합니다.

TextChoices django에서 는 상수를 보다 효율적으로 관리할 수 있으며, django 모델 필드와도 통합이 가능합니다.

from django.db import models

class StatusChoices(models.TextChoices):
    PENDING = "Pending"
    APPROVED = "Approved"
    REJECTED = "Rejected"

 

1. .value 없이도 값에 접근 가능

TextChoices는 Enum클래스와 달리 .value 없이도 값을 가져올 수 있고 문자열과의 직접적인 비교가 가능합니다.

print(StatusChoices.PENDING)
# Pending

"Pending" == StatusChoices.PENDING
# True

 

2. 모든 멤버의 값 또는 이름 가져오기

또한 values()names() 메서드를 제공하여 정의된 모든 멤버의 값(value) 또는 이름(name)을 쉽게 가져올 수 있습니다.

print(StatusChoices.values())
# ['Pending', 'Approved', 'Rejected']

print(StatusChoices.names())
# ['PENDING', 'APPROVED', 'REJECTED']

 

3. Django 모델 필드와의 호환성

TextChoices는 Django 모델 필드에서 choices 옵션으로 사용할 수 있으며 django admin 페이지, form에서 옵션 사용이 가능합니다.

class Work(models.Model):
    status = models.CharField(
        max_length=20,
        choices=StatusChoices.choices,
        default=StatusChoices.PENDING,
    )

works = Work.objects.filter(status=StatusChoices.APPROVED)

 

다만 필드 내부적인 validation은 따로 존재하지 않아 choices 이외의 다른 값을 저장하는 것은 가능합니다.

 

4. 가독성을 높이기 위한 레이블 제공

TextChoices는 각 멤버에 label을 지정할 수 있어 가독성을 높이며 admin 페이지나 폼에서도 표시가 가능합니다.

class StatusChoices(models.TextChoices):
    PENDING = "Pending", "대기중"
    APPROVED = "Approved", "승인됨"
    REJECTED = "Rejected", "거부됨"


print(StatusChoices.PENDING.label)
# 대기중