[DRF] - Serializer

오동훈·2022년 8월 31일
0

Django

목록 보기
8/23
post-thumbnail

1. Serializer

JSON으로 데이터를 주고 받을 수 있어야 한다. 이를 위해 DB 인스턴스를 JSON 데이터로 변환하거나, 반대로 JSON 데이터를 DB 인스턴스로 변환할 수 있어야 한다. 이를 목적으로 DRF에서 제공하는 클래스가 바로 serializer이다.

  • serializer / deserializer 되어야 하는 모델의 필드들이 정의됨
  • ModelSerializer를 사용해 대응하는 모델의 모든 필드, 또는 일부 정의 가능

2. Serializer 사용

  • serializer / deserializer 되어야 하는 필드 정의 필요
  • create(), update() 메소드 정의 필요
  • create(): serializer를 대상으로 save() 메소드를 호출해 DB 인스턴스를 생성할 때의 동작 정의
  • update(): serializer를 대상으로 save() 메소드를 호출하여 DB 인스턴스를 수정하고 할 때 동작 정의

사용 예

class BoardSerializer(serializers.Serializer):
        #시리얼라이저/디시리얼라이저 되어야 하는 필드들
        id = serializers.IntegerField(read_only=True)
        title = serializers.CharField(allow_blank=True, max_length=100)
        content= serializers.TextField(allow_blank=True, allow_null=True)

    def create(self, validated_data):
        #유효성 검사를 통과한 데이터들을 바탕으로 
        #새로운 DB 인스턴스를 생성하고 반환
        return Board.objects.create(**validated_data):

    def update(self, instance, validated_data):
        # 유효성 검사를 통과한 데이터들을 바탕으로 
        #기존의 DB 인스턴스를 수정하고 반환   
        instance.title = validated_data.get('title', instance.title)
        instance.content = validated_data.get('content', instance.content)

3. ModelSerializer 사용

  • serializer를 만들 시, 모델에 기반해 serializer 필드를 자동으로 만들어 줌
  • create(), update() 메소드가 기본으로 제공 됨으로, 세부 구현이 필요하지 않다면 정의할 필요가 없음

1. class meta 작성

    class Meta:
        model = "모델명"
        fields = "__all__" or "직접 명시"

2. 현재 존재하는 필드 외 추가하려는 필드가 있을 경우

serializer.SerializerMethodField()로 정의 필요

class BoardModelSerializer(serializers.ModelSerializer):
	time = serializers.SerializerMethodField()
	
    class Meta:    
		model = Board
		fields=('id', ‘title', 'content')
		get_time_of_selected_block(self, object):

4. serializer 이용 방법

1. model 생성

간단하게 모델을 생성해주자.

from django.db import models

# Create your models here.
class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

2. serializer 생성

create(), update() 메소드가 필요한 경우는 ModelSerializer를 사용하면 되고, 그게 아니라면 serializer를 임포트해서 사용하면 된당~~~

from rest_framework import serializers

class ArticleSerializer(serializers.Serializer):
    title = serializers.CharField()
    content = serializers.TextField()

3. ORM 및 serializing

queryset = Article.objects.all()  # ORM / DB -> QuerySet
serializer = ArticleSerializer(queryset) # serializer / QuerySet -> orderDict
serializer

>>> { 'title': 'hellow world', 'content': 'big world' }

4. JSONRender

JSONRender을 사용해 변환해도 좋고, json.dump()를 사용해 변환해주어도 상관없다~!!

from rest_framework.renderers import JSONRenderer

json = JSONRenderer().render(serializer.data)
json

>>> b'{ "title": "hellow world", "content": "big world" }

5. Deserializer 사용법

1. JSON To Dict

위에서 만든 json을 장고에서 활용하기 위한 딕셔너리 형태로 다시 바꾸는 방법은 아래와 같다.

import io
from rest_framework.parsers import JSONParser

stream = io.BytesIO(json)
data = JSONParser().parse(stream)

serializer = ArticleSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data

>>> { 'title': 'hellow world', 'content': 'big world' }

2. DB 생성 및 수정

serializer은 create와 update 메소드를 추가해 기능 추가가 가능하다.

  • Serializer에 create, update 포함 각 메소드 커스텀
  • ModelSerializer에 각 메소드 커스텀

ModelSerializer를 사용하는 방법도 존재하는데, 추가 기능을 넣으려면 오버 라이딩해서 사용하면 된다. 우선 Serializer에 기능 추가한 거 먼저 확인해보자.

from rest_framework import serializers

class ArticleSerializer(serializers.Serializer):
    title = serializers.CharField()
    content = serializers.TextField()
    def create(self, validated_data):
        return Article.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.content = validated_data.get('content', instance.content)
        instance.save()
        return instance

.save() 사용법

View.py에서 사용할 때의 예이다.

- serializer = ArticleSerializer(data=data)
인자가 하나밖에 없기 때문에 ArticleSerializer 클래스의 create로직이 사용된다.
create 메서드에 의해 DB에 생성이 된다.

- serializer = ArticleSerializer(article, data=data)
인자가 둘이기 때문에 ArticleSerializer 클래스의 update로직이 사용된다.
article은 models.py에서 정의한 Article의 인스턴트이다.
update로직에 의해 DB 값들이 수정된다.

serializer를 만들었으니 serializer.save()를 사용해서 실행하면 된다. 이때 아래와 같이 save에 인자를 추가해서 validated_data의 인수로 포함시키기도 가능하다.

serializer.save(owner=request.user)

is_valid()

deserializer을 하여 데이터에 접근하거나 DB에 저장할 때는 반드시 is_valid()를 호출해서 확인을 해줘야 한다. 다음은 공식 문서인데 함 봐보자

serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}

CommentSerializer에 데이터를 넣어서 serializer를 만들어주었다. 그리고 is_valid()를 했는데 False라고 나온 것을 확인할 수 있다. is_valid()가 False인 경우에 error속성을 사용 가능하다. 따라서 serializer.errors 통해 valid 검증이 False인 이유를 알 수 있다. 검증 실패 이유는 email의 형식이 잘못되었고, created는 필수 필드인데 없다는 것을 알 수 있다.

raise_exception=True를 인자로 아래와 같이 추가하는 것도 가능하다.

serializer.is_valid(raise_exception=True)

raise_exception=True을 추가하면 , is_valid의 값이 False라면 400 response를 반환해준다.

required=False

equired=False에 대한 설명이 부족하다 판단되어 아래와 같은 내용을 통해 추가 설명하려고 한다. 코드를 보자.

user = UserSerializer(required=False)

모든 칼럼을 다 넣어야 하지만, required=False를 넣으면 일부 칼럼에 None이 포함되더라도 error가 발생하지 않는다.

기본적으로 serializer는 모든 필수 필드의 값을 전달해야 합니다. 그렇지 않으면 유효성 검사 오류가 발생합니다. 그러나 수정 상황에서는 무든 필수 필드를 넣을 필요 없이 수정할 필드만 넣어주면 된다. 그때 사용하는 것이 partial=True이다. 아래와 같이 사용하면 된다.

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True)

many=True

기본적으로 BookSerializer의 인자로 queryset과 many=True가 들어가 있는 것을 알 수 있다. 그러나 보통 serializer 모델에 대입하는 인자는 하나의 객체 인스턴스여야 한다. 따라서 queryset이나, 객체 리스트를 넣으면 에러가 발생한다. 이때, 쿼리 셋이나 객체로 생성된 리스트를 하용하는 인자가 many=True이다.

queryset = Book.objects.all()
serializer = BookSerializer(queryset, many=True)
serializer.data
# [
#     {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'},
#     {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'},
#     {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'}
# ]

6. 이외 유용하게 쓸만한 Field

1. SerializerMethodField

우선 Serializer Method Field는 Model에 있는 필드이든 아니든 상관없이 사용 가능하다. 만약에 Model에 정의되어 있는 필드라면 새롭게 재정의가 되는 것이고, 그렇지 않다면 Model에 존재하지 않은 내용을 추가로 serializer에 추가해 반영시킬 수 있다. 그게 바로 SerializerMethodField이다.

만약에 DB에 비밀번호같은 값들을 암호화해서 저장했다고 가정해보자. 그 값을 조회한다 했을 때 암호화 한 값을 보여주면 안되기때문에 이런 작업들을 serializer 단에서 처리해보려고 한다.

임의로 DB의 암호화 된 값을 복호화 한다고 가정해보자.

class PasswordSerializer(serializers.ModelSerializer):
    password = serializers.SerializerMethodField('get_password')
    
    def get_password(self, instance):
        return cipher.decrypt_str(instance.password) # 대충 복호화 한다는 내용으로 생각해주기~

    class Meta:
        model = Location
        fields = ('id', 'name', 'password')

class 내부에 함수를 만들어 SerializerMethodField로 호출한다면, Password는 재정의 되어 복호화 된 값으로 날려줄 수 있습니다.

Django Docs - SerializerMethodField


요약하면 다음 그림과 같이 생각하면 된다!


참고 자료 📩
Django Docs - SerializerMethodField

profile
삽질의 기록들🐥

0개의 댓글