[Django REST Framework] Serializers 정리
Serializers: 쿼리셋이나 모델 instance 등 복잡한 데이터를 JSON, XML 등의 content type들로 변환해주며, 역으로 JSON, XML 등의 데이터를 다시 쿼리셋, 모델 인스턴스로 변환해준다.(deserialize)
serializer.is_valid()
create, update 와 같이 deserialize 과정이 필요할 때 유효성 검사를 위해 호출해야 하는 함수
- 모델에서 지정한 필드 타입과 필드 조건(Unique=True, blank=False 등)에 충족하는 데이터인지 검사
- 조건을 충족하면 validated_data에 유효성을 통과한 데이터를 넣어준다.
- 이후 serializer.save()를 수행하면 리소스가 생성되거나 업데이트 된다.
serializer.is_valid() 에러 만들기
데이터가 유효성 검사를 통과하지 못하면 에러 응답을 해야 하는데 단순히 다음과 같이 만들면 유효성 검사를 통과하지 못할 경우 메시지 없이 500(내부 서버 오류) 상태 코드를 반환하게 된다.
serializer = RegisterSerializer(data=request.data)
serializer.is_valid()
serializer.save()
return Response({'message': message.REGISTER_SUCCESS}, status=status.HTTP_201_CREATED)
- if 문을 사용한 에러 처리
serializer = RegisterSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message': message.REGISTER_SUCCESS}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
위 코드와 같이 if문을 사용하여 유효성 검사가 False일 때 에러 처리를 할 수 있다.
serializer.errors를 통해 key, value 형태로 유효성을 통과하지 못한 필드와 그 이유(ex. "user with this email already exist")가 담겨 응답 메시지로 보내진다.
- raise_exception을 사용한 에러 처리
serializer = RegisterSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response({'message': message.REGISTER_SUCCESS}, status=status.HTTP_201_CREATED)
위 코드처럼 serializer.is_valid(raise_exception=True)
를 사용하면 코드를 줄이고 에러 처리를 할 수 있다. 유효성 검사를 통과 못하면 알아서 serializer.errors와 함께 상태 코드 역시 따로 지정할 필요없이 400 코드를 반환하게 된다.
serializer.save()
유효성 검사를 통과한 데이터(validated_data)는 serializer.save()로 넘겨지는데 리소스가 없는 경우 create(), 있는 경우 update()를 하게 된다.
# serializer.save() 내부 코드 중 일부
# 기존에 존재하는 리소스이면 update, 아니면 create로 처리
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else:
self.instance = self.create(validated_data)
assert self.instance is not None, (
'`create()` did not return an object instance.'
)
create, update 함수는 오버라이딩을 통해 조건을 추가할 수 있다.
from django.contrib.auth.hashers import make_password
class RegisterSerializer(serializers.ModelSerializer):
security_code = SecurityCodeSerializer(read_only=True)
password2 = serializers.CharField(max_length=128, read_only=True)
class Meta:
model = User
fields = [
'id',
'email',
'password',
'password2',
'nickname',
'name',
'phone',
'security_code'
]
def create(self, validated_data):
validated_data['password'] = make_password(validated_data['password'])
return super().create(validated_data)
위와 같이 리소스를 생성할 때 serializers 클래스에서 create 함수를 작성하고 조건을 추가해준다.(여기서는 password가 해싱되어 저장하도록 함), update 함수도 동일한 방식으로 수정.
- 차이점
- create()는 validated_data 1개의 인자를 받는다.
- update()는 instance와 validated_data 2개의 인자를 받고 다시 instance를 반환한다.(기존에 존재하는 리소스를 업데이트 하는 것이기 때문에 해당 instance가 필요함)
#update 예시
def update(self, instance, validated_data):
new_password = make_password(validated_data['password'])
instance.password = new_password
instance.save()
return instance
validation
is_valid()를 통한 유효성 검사 이외에도 사용자 정의에 의한 유효성 검사를 할 수 있다. 순서상으로는 모델에서 지정한 필드 타입/조건에 대한 유효성 검사를 먼저 진행한 다음 사용자 정의 유효성 검사가 진행된다.
object_level validation
여러 필드에 대한 접근이 필요할 때 사용하는 validation으로 validate() 함수를 통해 만들 수 있다.
class ResetPasswordSerializer(serializers.ModelSerializer):
security_code = SecurityCodeSerializer(read_only=True)
password2 = serializers.CharField(read_only=True)
class Meta:
model = User
fields = [
'security_code',
'email',
'password',
'password2'
]
def validate(self, data):
input_password = data['password']
input_email = data['email'].split("@")[0]
nickname = User.objects.get(email=data['email']).nickname
if not 7 < len(input_password) < 13:
raise serializers.ValidationError(message.PASSWORD_LENGTH_ERROR)
if not any(char.isdigit() for char in input_password):
raise serializers.ValidationError(message.PASSWORD_COMBINATION_ERROR)
if not any(char.isalpha() for char in input_password):
raise serializers.ValidationError(message.PASSWORD_COMBINATION_ERROR)
if input_password in input_email \
or input_email in input_password:
raise serializers.ValidationError(message.PASSWORD_UNIQUE_ERROR)
if input_password in nickname \
or nickname in input_password:
raise serializers.ValidationError(message.PASSWORD_UNIQUE_ERROR)
return data
위와 같이 비밀번호 재설정을 위한 유효성 검사가 필요하고 여러 필드에 대한 접근이 필요할 때 validate()함수로 object-level의 유효성 검사를 만들 수 있다.
field_level validation
하나의 필드에 대한 유효성 검사를 진행할 때는 validate_필드명(self, value)
형식으로 field-level 유효성 검사를 할 수 있다.
class PhoneVerifySerializer(serializers.ModelSerializer):
class Meta:
model = PhoneVerification
fields = [
'id',
'phone',
'security_code'
]
def validate_phone(self, value):
if any(num.isalpha() for num in value):
raise serializers.ValidationError(message.PHONE_NUMBER_ERROR)
return value
field-level이기 때문에 인자로 받는 value는 phone 데이터이다.
Author And Source
이 문제에 관하여([Django REST Framework] Serializers 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dhleeone/Django-REST-Framework-Serializers-정리저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)