DRF - Serializers [2]

Dongwoo Kim·2022년 10월 7일
0

DRF

목록 보기
8/9
post-custom-banner

이전 포스팅에서 기본적인 Serializers에 대해 알아보았다.
오늘은 serializer에 새로운 field를 추가해보록 하자.

1. SerializerMethodField

SerializerMethodField를 이용하면 serializer에 임의로 원하는 field를 추가할 수 있다. (이미 존재하는 field를 변경할 수도 있다.)

📌 예시


유저 정보 조회 시 유저가 작성한 게시글의 개수를 포함시켜보자.

1) serializer 수정

  • post_count 라는 필드를 SerializerMethodField로 선언하고
  • get_을 붙여서 get_post_count라는 함수로 해당 필드가 어떤 값을 반환하는지 정의한다.
  • get_post_count 함수에서 objserialzer에 넣은 UserModel이다.
# user/serializers.py

from rest_framework import serializers
from user.models import User as UserModel

class UserModelSerializer(serializers.ModelSerializer):
    """
        유저 모델 Serializer
    """

    post_count = serializers.SerializerMethodField()

    def get_post_count(self, obj):
        post_count = obj.post_set.all().count()
        return post_count

    class Meta:
        model = UserModel
        fields = ['id', 'email', 'username', 'password', 'post_count']

        extra_kwargs = {
            'password': {'write_only': True}
        }  

2) 응답 데이터 확인


2. ForeignKey 나타내기

ForeignKey를 가지고있는 경우 해당 모델의 serializerfield로 포함시킬 수 있다.

📌 예시


게시글이 ForeignKey로 가지고 있는 유저(작성자)의 정보를 나타내보자.

1) Default

기본적으로 ForeignKey는 DB에 id값으로 저장되기 때문에 그대로 id로 표현된다.

  • serailzer 정의
# post/serializers.py

from rest_framework import serializers

from post.models import Post as PostModel

class PostModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = PostModel
        fields = ["id", "title", "content", "user", 
                  "views", "is_active", "created_date"]
  • view 정의
# posts/views.py

from rest_framework import status, exceptions
from rest_framework.views import APIView
from rest_framework.response import Response

from post.models import Post as PostModel
from post.serializers import PostModelSerializer

# 게시글 View
class PostView(APIView):
    # 게시글 상세 조회
    def get(self, request, post_id):
        post_obj = PostModel.objects.get(id=post_id)
        post_info = PostModelSerializer(post_obj).data

        return Response(post_info, status=status.HTTP_200_OK)
  • 응답 데이터

2) SerializerMethodField

앞서 알아본 것처럼 SerializerMethodField를 이용해서 임의로 설정할 수도 있다.

  • serailzer 정의
    : user 필드를 username으로 표현해보자
# posts/serializers.py

from rest_framework import serializers

from post.models import Post as PostModel

class PostModelSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()

    def get_user(self, obj):
        return obj.user.username

    class Meta:
        model = PostModel
        fields = ["id", "title", "content", "user", 
                  "views", "is_active", "created_date"]
  • 응답 데이터

3) Serializer

ForeignKey에 해당하는 모델의 serializer로 표현할 수 있다.

  • serailzer 정의
    : user 필드를 앞서 정의한 UserModelSerializer를 이용해서 나타내보자.

    from rest_framework import serializers
    
    from post.models import Post as PostModel
    from user.serializers import UserModelSerializer
    
    class PostModelSerializer(serializers.ModelSerializer):
       user = UserModelSerializer()
    
      class Meta:
          model = PostModel
          fields = ["id", "title", "content", "user", 
                    "views", "is_active", "created_date"]
  • 응답 데이터

💡 게시글 조회 시 UserModelSerializer로 표현한 유저정보와 유저 정보 조회시 UserModelSerializer로 표현한 정보가 같은 것을 확인해보자.


3. 모델 생성 시 고려사항

지금까지는 SerializerMethodFieldForeinKey의 정보를 조회할 경우에 대해서 알아보았다.
그렇다면 모델을 생성할 때는 SerializerMethodFieldForeinKey를 어떻게 표현해야할까?

1) SerializerMethodField

SerializerMethodField는 모델을 생성할 때(DB에 데이터를 저장할 때) 필요없는 정보이므로 신경쓰지않아도 된다. 즉, 무시한다.
하지만 ForeinKey처럼 이미 존재하는 fieldSerializerMethodField로 표현한다면 해당 정보를 따로 넣어줘야한다.

📌 예시

게시글 serialzertemp라는 필드와 user 필드를 SerializerMethodField로 나타냈을 경우, 게시글 생성 시

  • serialzer 정의
    temp 필드는 임의로 만든 필드
    user 필드는 ForeinKey인 유저의 정보를 username으로만 표현
# posts/serializers.py

from rest_framework import serializers

from post.models import Post as PostModel

class PostModelSerializer(serializers.ModelSerializer):
    temp = serializers.SerializerMethodField()
    user = serializers.SerializerMethodField()

    def get_temp(self, obj):
        return "This is SerializerMethodField"

    def get_user(self, obj):
        return obj.user.username

    class Meta:
        model = PostModel
        fields = ["id", "title", "content", "user", 
                  "views", "is_active", "created_date", "temp"]
  • view 정의
    temp는 DB에 저장할 때 필요없지만 user는 필요하기 때문에 request.user로 유저 정보를 받아서 넣어준다.
# post/views.py

# 게시글 View
class PostView(APIView):
    # 게시글 생성
    def post(self, request):
        user = request.user
        post_info = request.data

        serializer = PostModelSerializer(data=post_info)
        if serializer.is_valid():
        	serializer.save(user=user) # 유저 정보를 넣어준다
        	return Response(serializer.data, status=status.HTTP_200_OK)
    
        return Response({"error" : "게시글 생성 실패"}, status=status.HTTP_400_BAD_REQUEST)
  • 요청/응답 데이터

2) ForeignKey

ForeignKey는 모델 생성시 어떻게 해야할지 알아보자

2-1) Default

기본적으로 ForeignKey는 DB에 id값으로 저장되기 때문에 그대로 id로 표현되었다. 따라서 모델 생성시에도 id 값으로 넣어주면 된다.

  • serializer 정의
# post/serializers.py
from rest_framework import serializers

from post.models import Post as PostModel

class PostModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = PostModel
        fields = ["id", "title", "content", "user", 
                  "views", "is_active", "created_date"]
  • view 정의
# post/views.py

# 게시글 View
class PostView(APIView):
    # 게시글 생성
    def post(self, request):
        post_info = request.data  # user 정보도 request.data에 포함되어 있다.

        serializer = PostModelSerializer(data=post_info)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
    
        return Response({"error" : "게시글 생성 실패"}, status=status.HTTP_400_BAD_REQUEST)
  • 요청/응답 데이터

2-2) SerializerMethodField

ForeignKeySerializerMethodField로 표현한 경우는 앞에서 알아봤기 때문에 넘어가도록 한다.

2-3) Serializer

ForeignKey에 해당하는 모델의 serializer로 표현한 경우, 해당 모델을 생성할 때에는 ForeignKeyserialierread_only=True 속성을 넣어주고, SerializerMethodField 때와 같이 ForeignKey 정보를 따로 넣어줘야한다.

  • serializer 정의
# post/serializers.py
class PostModelSerializer(serializers.ModelSerializer):
    user = UserModelSerializer(read_only=True) # read_only=True

    class Meta:
        model = PostModel
        fields = ["id", "title", "content", "user", 
                  "views", "is_active", "created_date"]
  • view 정의
# post/views.py

# 게시글 View
class PostView(APIView):
    # 게시글 생성
    def post(self, request):
        user = request.user
        post_info = request.data

        serializer = PostModelSerializer(data=post_info)
        if serializer.is_valid(raise_exception=True):
            serializer.save(user=user) # 유저 정보를 따로 넣어준다.
            return Response(serializer.data, status=status.HTTP_200_OK)

        return Response({"error" : "게시글 생성 실패"}, status=status.HTTP_400_BAD_REQUEST)
  • 요청/응답 데이터

4. 추가 고려사항

  1. 유저 정보 조회 시 유저 객체 데이터가 가진 속성 이외의 정보도 알고 싶다면 어떻게해야할까?
    ex) 유저가 가진 게시글 개수

: SerializerMethodField를 이용한다

  1. 유저 생성 시 유저 정보가 유효한지 어떻게 검증할까?
    ex) 유저 아이디가 겹칠 경우 에러 발생 시
  1. 유저 생성 시 비밀번호는 어떻게 해시할까?
    • 현재 비밀번호는 문자열 그대로 저장되고 있지만 보안상 해시할 필요가 있다.
  1. 유저 정보를 수정하고 싶을 때도 Serializers를 이용할 수 있을까?

해당 고려사항에 대해서는 다음 포스팅에서 알아보도록 하자



profile
kimphysicsman
post-custom-banner

0개의 댓글