python/Django

DoesNotExist vs MultipleObjectsReturned - ORM 예외처리

Balang 2025. 5. 8. 18:49
728x90

ORM을 사용해서 개발을 하다 보면 아래 오류가 종종 발생하고는 합니다.

User.DoesNotExist: User matching query does not exist.

 

처음에는 ORM이 잘 작동했지만 서비스에서 트랙픽이 증가하고, 데이터가 누적되기 시작하면서

예외가 빈번하게 발생했습니다.

 

먼저 발생원인에 대해 확인하면

get( ) 메서드의 핵심 특징을 알아야합니다.

 

get( )은 단 하나의 레코드만 존재할 때만 성공합니다.

그 외엔 무조건 예외를 발생시킵니다.

예외 발생 조건 원인
DoesNotExist 해당 조건에 맞는 결과가 0개 삭제되었거나 조건이 잘못됨
MultipleObjectsReturned 결과가 2개 이상일 때 중복 데이터 또는 unique 제약 누락

 

예외를 처리하지 않으면 서버에서 500에러가 발생해 사용자 입장에서는 서버 문제처럼 보입니다.

get( )은 취약한 API 엔드포인드를 만들 위험이 있습니다.

데이터 구조 자체의 결함(중복, 제약조건 누락)도 드러나지 않고 서비스만 불안정해줄 수 있습니다.

 

해결방법

1. 예외를 명시적으로 처리 (try - except)

from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned

try:
    user = User.objects.get(email=email)
except User.DoesNotExist:
    return JsonResponse({'error': '해당 이메일의 사용자가 없습니다.'}, status=404)
except User.MultipleObjectsReturned:
    return JsonResponse({'error': '중복된 이메일이 존재합니다.'}, status=400)

 

API에서는 무조건 404 or 400으로 분리해서 명확한 응답을 줘야 합니다.

 

 

2. filter().first()로 우회 (예외 없이 안전하게)

user = User.objects.filter(email=email).first()

if not user:
    return JsonResponse({'error': '사용자를 찾을 수 없습니다.'}, status=404)

 

결과가 여러 개여도 첫 번째 값만 반환해서 예외가 발생하지 않습니다.

중복 방지 설계가 되어 있어야 사용할 수 있습니다.

 

 

3. filter().count()로 명확하게 개수 검사

qs = User.objects.filter(email=email)
count = qs.count()

if count == 1:
    user = qs.first()
elif count == 0:
    return JsonResponse({'error': '사용자를 찾을 수 없습니다.'}, status=404)
else:
    return JsonResponse({'error': '중복된 사용자가 존재합니다.'}, status=400)

 

느리지만 가장 정확한 개수 기반으로 분기가 가능합니다.

 

 

4. 애초에 모델에 제약조건 걸기 (unique=True)

class User(models.Model):
    email = models.EmailField(unique=True)  # 중복 방지

가장 확실한 방법입니다.
DB 차원에서 중복 자체를 원천 차단한다.

나중에 get()도 안전하게 사용 가능합니다.

 

상황 방식
get()로 단일 결과를 기대 반드시 try-except로 감싸기
중복 발생 가능성 있음 filter().first()로 우회
정확한 결과 필요 filter().count() 후 분기
구조적 중복 방지 unique 제약조건 설정

 

 

정리

Django ORM의 get()은 매우 편리하지만,
예외가 발생할 가능성이 매우 높은 메서드입니다.
실무에서는 반드시 DoesNotExist, MultipleObjectsReturned를 고려하고
대응 전략을 사전에 구조적으로 설계해야 합니다.

 

 

참고 자료 (Reference)

 

728x90
반응형