내배캠/TIL
TIL/36/20230501
woongpang
2023. 5. 1. 21:20
728x90
serializer 활용
serializer는 데이터 직렬화 외에도 data validation, create, update 기능을 사용할 수 있다.
validator
- serializer에서는 기본적으로 Meta class 내부 field에 포함되어 있는 항목에 맞게 validate를 진행한다.
- validator 예시(views.py)
from user.serializers import UserSerializer
...
class UserView(APIView):
def post(self, request):
# serializer의 data 인자에는 model로 지정 된 테이블의 field:value를 dictionary로 넘겨준다.
user_serializer = UserSerializer(data=request.data)
# serializer validator를 통과하지 않을 경우 .is_valid()가 False로 return된다.
if user_serializer.is_valid():
# validator를 통과했을 경우 데이터 저장
user_serializer.save()
return Response({"message": "정상"}, status=status.HTTP_200_OK)
# .errors에는 validator에 실패한 필드와 실패 사유가 담겨져 있다.
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# sample request.data
"""
{
"username": "new_user",
"password": "MyL0ve1yP@ssw0rd",
"fullname": "myname",
"userprofile": {
"introduction": "자기소개입니다.",
"birthday": "2000-1-01",
"age": 30
},
"trash": "zczxcvx"
}
"""
- serializer에서 사용 가능한 옵션들
class UserSerializer(serializers.ModelSerializer):
# 외래 키 관계에 있는 필드의 required를 설정하고 싶을 경우 인자로 넘겨줘야 한다.
userprofile = UserProfileSerializer(required=False) # default : True
...
class Meta:
...
# 각 필드에 해당하는 다양한 옵션 지정
extra_kwargs = {
# write_only : 해당 필드를 쓰기 전용으로 만들어 준다.
# 쓰기 전용으로 설정 된 필드는 직렬화 된 데이터에서 보여지지 않는다.
'password': {'write_only': True}, # default : False
'email': {
# error_messages : 에러 메세지를 자유롭게 설정 할 수 있다.
'error_messages': {
# required : 값이 입력되지 않았을 때 보여지는 메세지
'required': '이메일을 입력해주세요.',
# invalid : 값의 포맷이 맞지 않을 때 보여지는 메세지
'invalid': '알맞은 형식의 이메일을 입력해주세요.'
},
# required : validator에서 해당 값의 필요 여부를 판단한다.
'required': False # default : True
},
}
- view에서 사용 가능한 옵션들
# serializer의 인자에 object를 넣어 직렬화 된 데이터를 가져올 수 있다.
user = request.user
return Response(UserSerializer(user).data, status=status.HTTP_200_OK)
# object와 마찬가지로 queryset을 인자로 넣어 여러개의 직렬화 된 데이터를 가져올 수 있다.
hobbys = Hobby.objects.all()
# queryset을 인자로 넣을 경우 many=True 설정 필요하다.
return Response(HobbySerializer(hobbys, many=True).data, status=status.HTTP_200_OK)
# partial을 True로 설정할 경우 required field에 대한 validation을 수행하지 않는다.
# 주로 일부 필드를 update 할 때 사용된다.
user_serializer = UserSerializer(data=request.data, partial=True)
# raise_exception을 True로 설정할 경우 validation을 통과하지 못했을 때 exception을 발생시킨다.
user_serializer = UserSerializer(data=request.data, raise_exception=True)
- custom validator
- custom validator는 validator 이후에 동작한다.
- custom validator는 validator와 별개로 동작한다.
- validator는 데이터의 requierd, invalid 등을 판단하고 custom validator에서는 사용자가 원하는 validation을 추가로 검증 할 수 있다.
- custom validator 예시(serializers.py)
...
class UserSerializer(serializers.ModelSerializer):
...
# validate 함수 선언 시 serializer에서 자동으로 해당 함수의 validation을 해줌
def validate(self, data):
# custom validation pattern
if data.get("userprofile", {}).get("age", 0) < 12:
# validation에 통과하지 못할 경우 ValidationError class 호출
raise serializers.ValidationError(
# custom validation error message
detail={"error": "12세 이상만 가입할 수 있습니다."},
)
# validation에 문제가 없을 경우 data return
return data
...
creator
- serializer에서는 validation을 통과할 경우 .save() 메소드를 통해 검증 된 오브젝트를 생성 할 수 있다.
- 사용 방법은 validator 예시에 작성한 코드와 동일하다.
- custom creator 코드는 기존 create 코드를 덮어쓰며, custom creator를 생성할 경우 기존 create 코드는 동작하지 않는다.
- custom creator (serializers.py)
...
class UserProfileSerializer(serializers.ModelSerializer):
# hobby는 데이터를 직렬화 할 때, get_hobbys는 profile을 등록할 떄 사용된다.
hobby = HobbySerializer(many=True, required=False, read_only=True)
get_hobbys = serializers.ListField(required=False)
class Meta:
model = UserProfile
fields = ["birthday", "age", "introduction", "hobby", "get_hobbys"]
class UserSerializer(serializers.ModelSerializer):
userprofile = UserProfileSerializer()
def create(self, validated_data):
# object를 생성할때 다른 데이터가 입력되는 것을 방지하기 위해 미리 pop 해준다.
user_profile = validated_data.pop('userprofile')
get_hobbys = user_profile.pop("get_hobbys", [])
# User object 생성
user = User(**validated_data)
user.save()
# UserProfile object 생성
user_profile = UserProfile.objects.create(user=user, **user_profile)
# hobby 등록
user_profile.hobby.add(*get_hobbys)
user_profile.save()
...
class Meta:
model = User
fields = ["username", "password", "fullname", "email", "userprofile"]
...
# sample request data
"""
{
"username": "user_name",
"password": "H0t$ix",
"fullname": "이름",
"email": "sample@email.com",
"userprofile": {
"introduction": "자기소개입니다.",
"birthday": "2000-1-01",
"age": 13,
"get_hobbys": [3,4,5,6]
}
}
"""
updater
- serializer를 사용해 기존 데이터들 쉽게 업데이트 할 수 있다.
from user.serializers import UserSerializer
...
class UserView(APIView):
def post(self, request):
user = request.user
if user.is_anonymous:
return Response({"error": "로그인 후 이용해주세요", status=status.HTTP_400_BAD_REQUEST}
# 기본적인 사용 방법은 validator, creater와 다르지 않다.
# update를 해줄 경우 obj, data(수정할 dict)를 입력한다.
# partial=True로 설정해 주면 일부 필드만 입력해도 에러가 발생하지 않는다.
user_serializer = UserSerializer(user, data=request.data, partial=True)
if user_serializer.is_valid():
# validator를 통과했을 경우 데이터 저장
user_serializer.save()
return Response({"message": "정상"}, status=status.HTTP_200_OK)
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
custom update 코드는 기존 update 코드를 덮어쓰며, custom updater를 생성할 경우 기존 create 코드는 동작하지 않는다.
custom update 예시(views.py)
class UserSerializer(serializers.ModelSerializer):
userprofile = UserProfileSerializer()
...
def update(self, instance, validated_data):
# instance에는 입력된 object가 담긴다.
for key, value in validated_data.items():
if key == "password":
instance.set_password(value)
continue
setattr(instance, key, value)
instance.save()
return instance
...
class Meta:
model = User
fields = ["username", "password", "fullname", "email", "userprofile"]
728x90