반응형
🚨 문제 상황
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 정합성 | ✅ 완벽하게 해결 |
반응형
'Dev > Python' 카테고리의 다른 글
[FastAPI] DELETE 요청 시 JSON이 아닌 Path Param으로 값 전달하는 방법 (0) | 2025.03.27 |
---|---|
[FastAPI] Swagger UI에서 POST 요청 시 JSON 입력창으로 바뀌는 이유 (0) | 2025.03.26 |
[Python] 주석(Comment) vs. 독스트링(Docstring) 차이점 (0) | 2025.03.24 |
[FastAPI] Schemas Models 와 다른 경우 예제 (0) | 2025.03.22 |
[FastAPI] Schemas 예제 개념 정리 (0) | 2025.03.21 |