model
에 사용 될 테이블을 적어주고, field
에 사용될 필드를 적어준다.extra_kwargs
, read_only_fields
와 같은 옵션을 통해 다양한 설정이 가능하다.serializers.py
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
# serializer에 사용될 model, field지정
model = User
# 모든 필드를 사용하고 싶을 경우 fields = "__all__"로 사용
fields = ["username", "password", "fullname", "email"]
views.py
from rest_framework.response import Response
from rest_framework import status
from user.serializers import UserSerializer
def get(self, request):
user = request.user
# serializer에 queryset을 인자로 줄 경우 many=True 옵션을 사용해야 한다.
serialized_user_data = UserSerializer(user).data
# context= 를 통해 원하는 데이터를 serializer에 넘겨주고, self.context를 사용해 호출 가능하다.
# serialized_user_data = UserSerializer(user, context={"some_key": "some_value"}).data
return Response(serialized_user_data, status=status.HTTP_200_OK)
# return data
"""
{
"username": "user",
"password": "pbkdf2_sha256$320000$u5YnmKo9luab9csqWpzRsa$pKfqHnBiF5Rgdo1Mj9nxNOdhpAl9AhPVXFPXkbPz7Mg=",
"fullname": "user's name",
"email": "user@email.com"
}
"""
serializer.py
)class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = "__all__"
class UserSerializer(serializers.ModelSerializer):
"""
외래 키는 UserProfile에서 User 테이블로 설정되어 있지만
one to one 필드기 때문에 userprofile이라는 명칭으로 역참조가 가능하다.
"""
userprofile = UserProfileSerializer()
class Meta:
model = User
fields = ["username", "password", "fullname", "email", "userprofile"]
SerializerMethodField
를 활용해 원하는 필드를 추가하고, 더 나아가서 여러 serializer들을 함께 사용할 수 있다.serializers.py
)class HobbySerializer(serializers.ModelSerializer):
# serializers.SerializerMethodField()를 사용해 원하는 필드를 생성한다.
same_hobby_users = serializers.SerializerMethodField()
def get_same_hobby_users(self, obj):
user_list = []
for user_profile in obj.userprofile_set.all():
user_list.append(user_profile.user.username)
return user_list
class Meta:
model = Hobby
fields = ["name", "same_hobby_users"]
class UserProfileSerializer(serializers.ModelSerializer):
# 외래 키 관계로 이어져 있는 필드는 Serializer를 바로 호출할 수 있다.
hobby = HobbySerializer(many=True)
class Meta:
model = UserProfile
fields = "__all__"
class UserSerializer(serializers.ModelSerializer):
# One-to-one 관계에서는 fk처럼 사용 가능하다.
userprofile = UserProfileSerializer()
**** class Meta:
model = User
fields = ["username", "password", "fullname", "email", "userprofile"]
# views.py
...
class UserView(APIView)
def get(self, request):
user = request.user
return Response(UserSerializer(user).data, status=status.HTTP_200_OK)
# response data
"""
{
"username": "admin",
"password": "pbkdf2_sha256$320000$u5YnmKo9luab9csqWpzRsa$pKfqHnBiF5Rgdo1Mj9nxNOdhpAl9AhPVXFPXkbPz7Mg=",
"fullname": "zxcv",
"email": "zxv@asd.com",
"userprofile": {
"birthday": "2022-06-08",
"age": 1,
"introduction": "asdac",
"hobby": [
{
"name": "독서",
"same_hobby_users": [
"user1",
"user2",
"user3"
]
}
]
}
}
"""
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"
}
"""
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
},
}
# 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)
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
...
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]
}
}
"""
views.py
)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)
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"]