본문 바로가기

[FastAPI + PostgreSQL] psycopg2 ENUM 에러 "GENERAL" 해결기

@Jeeqong 2025. 3. 25. 02:28
반응형

🚨 문제 상황

FastAPI + SQLAlchemy + PostgreSQL 프로젝트에서 아래와 같은 에러 발생:

sqlalchemy.exc.DataError: (psycopg2.errors.InvalidTextRepresentation)
invalid input value for enum excludewordtype: "GENERAL"

▶️ 실제 SQL 로그

WHERE exclude_words.type = 'GENERAL'

하지만 PostgreSQL ENUM 타입은 아래처럼 소문자로 정의되어 있었음:

SELECT unnest(enum_range(NULL::excludewordtype));
-- 결과:
-- brand
-- general

❓ 왜 이런 문제가 발생했을까?

✔️ 원인 1. Python Enum의 .name vs .value

Python Enum 객체에는 아래 두 가지 속성이 있음:

class ExcludeWordType(str, Enum):
    GENERAL = "general"

ExcludeWordType.GENERAL.name   # → "GENERAL"
ExcludeWordType.GENERAL.value  # → "general"

SQLAlchemy는 기본적으로 .name을 사용해서 문자열로 변환하기 때문에,

DB에는 "GENERAL"을 넣으려고 함 → PostgreSQL은 "general"만 허용하니까 에러 발생.


❗ 실패한 접근들

  • data.type.value로 강제 전달해도 쿼리 안에서 "GENERAL"로 변환됨
  • Enum을 하나로 통일해도 해결되지 않음
  • FastAPI / Pydantic / SQLAlchemy가 모두 Enum.value를 쓰도록 강제해야 함

✅ 최종 해결 방법

SQLAlchemy Enum 컬럼 정의에서 아래와 같이 설정:

from sqlalchemy import Enum as SAEnum
from app.db.enums import ExcludeWordType

type = Column(
    SAEnum(
        ExcludeWordType,
        name="excludewordtype",
        native_enum=False,
        values_callable=lambda x: [e.value for e in x]  # value만 사용하도록 지정
    ),
    nullable=False,
    default=ExcludeWordType.GENERAL
)

✔️ 설명

 

옵션 설명
native_enum=False SQLAlchemy가 PostgreSQL ENUM을 직접 쓰지 않고, 문자열처럼 처리
values_callable=... Enum 객체에서 .value만 추출해서 저장하도록 강제

💥 이후 결과

  • data.type에 Enum 객체 그대로 넘겨도 "general"로 잘 저장됨
  • SELECT / INSERT / 중복 체크 모두 정상 작동
  • PostgreSQL ENUM 정의와 충돌 없음
  • repr(data.type) → <ExcludeWordType.GENERAL: 'general'> 정상 유지

🔖 정리 요약

 

항목 해결 상태
Enum .name → "GENERAL" ❌ PostgreSQL과 충돌
Enum .value → "general" ✅ DB와 일치
SQLAlchemy 변환 ✅ values_callable로 강제
FastAPI + SQLAlchemy Enum 정합성 ✅ 완벽하게 해결

 

반응형
Jeeqong
@Jeeqong :: JQVAULT

Jeeqong's vault : 정보/기록을 쌓아두는 공간 웹개발 포스팅 일상 리뷰를 기록하는 공간입니다.

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차