본문 바로가기

[FastAPI] 카테고리 중복 체크 시 null / 빈 문자열 처리 방법

@Jeeqong 2025. 4. 5. 11:24
반응형

📌 문제 상황

FastAPI에서 카테고리를 다음과 같은 구조로 저장한다고 가정하자.

  • main_category: 대분류 (필수)
  • sub_category: 중분류 (선택)
  • sub_sub_category: 소분류 (선택)

DB 설계 시 sub_category, sub_sub_category는 nullable=True 로 되어 있고,

입력값이 없으면 None 혹은 ""(빈 문자열)로 들어올 수 있다.

하지만!

중복 체크를 할 때 "None"과 ""를 구분하지 않으면

실제로는 같은 카테고리인데 중복으로 인식되지 않는 문제가 발생할 수 있다.


⚠️ 실제 발생 가능한 예시

POST /categories

{
  "main_category": "생활/건강",
  "sub_category": "생활용품",
  "sub_sub_category": ""
}

→ 이 경우 DB에는 sub_sub_category = ""로 저장됨.

POST /categories

{
  "main_category": "생활/건강",
  "sub_category": "생활용품"
}

→ 이 경우엔 sub_sub_category = null 로 들어감.

둘 다 소분류 없음을 의미하지만, 중복 체크 로직에서는 다르게 인식될 수 있다.


✅ 해결 방법

1. 빈 문자열을 None으로 변환하거나, None을 빈 문자열로 정규화한다.

이를 통해 비교 기준을 일관되게 만들 수 있다.


2. 정규화 유틸 함수 정의

def normalize_empty_str(value: Optional[str]) -> str:
    """None 또는 공백을 빈 문자열로 정규화"""
    return value or ""

3. 중복 체크 함수에 적용

def is_category_already_exists(
    db: Session,
    main: str,
    sub: Optional[str],
    sub_sub: Optional[str]
) -> bool:
    """카테고리 중복 체크 (빈값 포함 비교 처리)"""

    sub = normalize_empty_str(sub)
    sub_sub = normalize_empty_str(sub_sub)

    return (
        db.query(Category)
        .filter(
            Category.main_category == main,
            Category.sub_category == sub,
            Category.sub_sub_category == sub_sub
        )
        .first()
        is not None
    )

4. 서비스 로직에서 심플하게 사용

if is_category_already_exists(
    db,
    data.main_category,
    data.sub_category,
    data.sub_sub_category,
):
    raise AlreadyExistsException("이미 존재하는 카테고리입니다.")

✨ 정리 요약

구분  의미  처리 방법
None 값이 아예 없음 빈 문자열로 변환하여 비교
"" 공백 문자열 None과 동일하게 처리
✔️ 해결책 normalize 함수 사용 중복 체크 일관성 확보

✅ 결론

  • null과 ""는 개발자가 보기엔 같지만, DB에선 다른 값이다.
  • 중복 검사, 유효성 체크 시 빈값 처리를 명확하게 정규화해야 한다.
  • 실수로 인한 중복 저장 방지를 위해, normalize 유틸을 적극 활용하자!
반응형
Jeeqong
@Jeeqong :: JQVAULT

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

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

목차