to_representation vs to_internal_value 오버라이드 기준
Serializer의 핵심 메서드인 to_representation과 to_internal_value의 역할과 오버라이드 시점을 명확히 구분하여 API 데이터 처리를 효율적으로 구현
Serializer 데이터 흐름
to_internal_value: 클라이언트 데이터 → Python 객체 (역직렬화)
호출 시점:
serializer.is_valid()실행 시입력: 원시 데이터 (JSON 등)
출력: Python 네이티브 데이터 타입
to_representation: Python 객체 → 클라이언트 데이터 (직렬화)
호출 시점:
serializer.data접근 시입력: 모델 인스턴스
출력: JSON 변환 가능한 dict
to_internal_value 오버라이드 시점
비표준 입력 형식 처리
Unix timestamp를 datetime으로 변환
복잡한 중첩 구조를 단순 값으로 변환
관계 객체 연결
ID 대신 username으로 User 객체 찾기
외래키 연결을 위한 커스텀 로직
def to_internal_value(self, data):
author_username = data.get('author_username')
if not author_username:
raise serializers.ValidationError({
'author_username': 'This field is required.'
})
try:
user = User.objects.get(username=author_username)
except User.DoesNotExist:
raise serializers.ValidationError({
'author_username': f'User with username "{author_username}" does not exist.'
})
internal_value = super().to_internal_value(data)
internal_value['author'] = user
return internal_valueto_representation 오버라이드 시점
출력 데이터 포맷 변경
날짜 형식 커스터마이징
숫자 포맷 변경
계산된 필드 추가
동적으로 생성되는 값
조건부 필드 노출
조건부 데이터 처리
사용자 권한에 따른 필드 숨김
민감 정보 필터링
def to_representation(self, instance):
representation = super().to_representation(instance)
# 날짜 포맷 변경
representation['created_at'] = instance.created_at.strftime('%Y년 %m월 %d일')
# 계산된 필드 추가
from django.utils import timezone
representation['is_new'] = timezone.now() - instance.created_at < timezone.timedelta(days=1)
return representation실무 주의사항
대안 우선 고려
단순한 출력 변경은 SerializerMethodField 사용
재사용이 필요한 복잡한 로직은 커스텀 필드 클래스 생성
성능 최적화
to_representation에서 DB 쿼리 발생 시 N+1 문제 주의
select_related, prefetch_related 활용
super() 호출 필수
기본 동작 유지하면서 부분 수정
DRF 기본 로직과의 호환성 보장
명확한 에러 처리
ValidationError 발생 시 구체적인 필드와 이유 명시
클라이언트 디버깅 편의성 제공
Last updated
