모델 시리얼라이저

웅평·2023년 6월 16일
0

모델 시리얼라이저란?

Serializer를 만들 때, 각 필드를 하나하나 정의해 주었다. 마치 모델을 다시 한 번 작성하는 것 같은 불편함이 있었다. 이 문제를 해결해 주는 것이 ModelSerializer이다.

ModelSerializer는 크게 3가지 기능을 제공

  • .create(), .update() 함수 기본으로 제공하여 다시 만들 필요 없음
  • Serializer를 위한 validator 제공 : ex) unique_together_validators
  • (의존하고 있는 모델에 기반해서) Serializer 필드를 자동으로 만들어 줌
class MovieSerializer(serializers.ModelSerializer):
    class Meta:
        model = 모델명
        fields = ['id', 'name']

class Meta 옵션
필수작성

  • model : 생성한 시리얼라이저가 어떤 모델을 사용할지 지정하는 옵션
  • fields : 모델 중 어떤 필드를 사용할지 작성하는 옵션
fields = ['id', 'name'] 직접명시
fields = '__all__' 전체 필드 가져옴
  • exclude : fields와 정반대인 옵션, 모델을 기준으로 어떤 필드를 제외할지 나타낸다
  • read_only_fields : id 필드와 같이 데이터베이스에서 기본으로 생성되는 필드에 read_only 옵션을 자동으로 추가하는데 그 외 필드(자동 생성되지 않는 필드)에 선택적으로 read_only를 추가할 때 사용
  • extra_kwargs : 양한 필드에 여러 옵션을 추가해야 할 경우

serializer로 정의해 줘야 되는 필드

  • 모델에 없는 필드를 추가하고 싶거나 모델에 있는 값을 변형해서 새로운 필드의 값으로 넣고 싶으면 serializer.SerializerMethodField()로 정의해 줌

Example
User 객체의 모델에는 full_name 필드만 있다고 가정 여기서 이름만 뽑아내서 JSON에 first_name을 추가

# Serializer된 User객체
"id" : 1,
"full_name": '{"first_name": "soms", "last_name": "kim"}',

JSON에는 full_name 필드에 해당하는 객체의 "full_name" 속성만 포함된다.
기본적으로 객체를 시리얼라이저를 통해 JSON으로 직렬화할 때
model 에 정의된 필드는 Serializer 클래스 안의 Meta 클래스(

class Meta:
    model = MODEL클래스이름
    ...

)에서 model = MODEL클래스이름 만 추가하면 자동으로 시리얼라이저 필드로 추가되지만
모델에 last_name 필드가 없어서 시리얼라이저 필드에 추가할 수가 없기 때문이다.

class UserSerializer(serializers.Serializer):
    full_name = JSONField
	last_name = serializers.SerializerMethodField() # 1. 필드 추가

    class Meta:
        model = User

    def get_first_name(self, obj): # 2. 메소드 추가. 이 메소드는 객체를 인자로 받고
        return obj.full_name['first_name'] # 객체의 full_name 속성 값에서 'last_name' 키 값을 리턴

SerializerMethodField 를 사용하면 객체의 모델에 first_name필드가 없음에도 불구하고 JSON에 first_name 속성도 포함할 수 있다.

"id" : 1,
"full_name": '{"first_name": "soms", "last_name": "kim"}',
"first_name : "soms"

Nested Relationships
ForeignKey 필드를 사용하고자 할 때, 기본적으로 아무런 설정이 없으면 참조하고 있는 pk 값을 가져온다. 만약 pk 값 외에 다른 값을 가져오고 싶다면, 아래와 같은 메소드를 이용할 수 있다.

1) String of related object / StringRelatedField Tutorial

  • ForgeignKey로 연결된 모델의 str 메소드에서 정의한 string를 리턴
  • 인자로 many=True, read_only=True 등을 가질 수 있음
class ArticleSerializer(serializers.ModelSerializer):
    ...
    author = serializers.StringRelatedField() 

API 호출 결과

models.py

class Journalist(models.Model):
    ...
    def __str__(self):
        return f"{ self.first_name } { self.last_name }"

2) All information of related object

  • 참조할 모델의 Serializer를 가져와서 사용 (참조할 Serializer가 더 위에 위치해야 참조할 수 있음)
  • 인자로 many=True, read_only=True 등을 가질 수 있음
  • Journalist <- Article이 정참조하는 관계 (1 : N)로서 ArticleSerializer에서 author를 참조할 수 있고, 반대로 JournalistSerializer에서 articles를 참조할 수 도 있음
class JournalistSerializer(serializers.ModelSerializer):
    ...
    # articles = ArticleSerializer(many=True, read_only=True)

class ArticleSerializer(serializers.ModelSerializer):
    ...
    author = JounalistSerializer(read_only=True)

API 호출 결과

이 필드는 Read only로만 사용된다. 비슷한 역할을 하는 모듈로 PrimaryKeyRelatedField가 있는데, 이 모듈은 타겟 모델의 primary key 값을 가져오게 된다.

Links of related object / HyperlinkedRelatedField()

  • HyperlinkedRelatedField는 ForgeignKey로 연결된 타겟 필드의 API url을 리턴
  • many, read_only, view_name 등 지정해 줘야 함.
    • 특히, view_name은 참조할 api의 url의 name을 명시해야 함
[serilaizers.py]
class JournalistSerializer(serializers.ModelSerializer):
  ...
  articles = serializers.HyperlinkedRelatedField(many=True,
             read_only=True, view_name="article-detail")


[views.py]
class JournalistListCreateAPIView(APIView):
    
  def get(self, request):
    journalists = Journalist.objects.all()
    serializer = JournalistSerializer(journalists, many=True,
                 context={'request': request})
    return Response(serializer.data)

참고
https://www.django-rest-framework.org/api-guide/serializers/#including-extra-context
https://velog.io/@jcinsh/DRF-5-ModelSerializer
https://velog.io/@phyyou/DRF-%EA%B3%B5%EB%B6%80%ED%95%98%EA%B8%B0-6-ModelSerializer

0개의 댓글