시리얼라이저(Serilaizer)?
시리얼라이저는 모델 인스턴스나 QuerySet과 같은 데이터를 JSON 파일로 변환하는 작업(Serialize) 또는 JSON을 모델 인스턴스로 변환하는 작업(Deserialize)을 할 때 쓰이는 매개체다.
시리얼라이저 구현
우리가 이전에 만들었던 Question과 Choice 모델을 통해서 시리얼라이저를 구현한 뒤, Serialize와 Deserialize를 시도해보자.
우선 터미널 창에서 mysite 폴더로 이동한 다음, 아래와 같은 명령어를 입력한다. polls라는 app을 api형태로 구현할 것이기 때문에, app 이름을 polls_api로 설정했다.
python manage.py startapp polls_api
mysite 폴더 내부를 살펴보면 아래와 같이 polls_api 폴더가 새로 생성된 것을 알 수 있다. 이제 본격적으로 시리얼라이저를 구현해보자.
먼저 polls_api 폴더 내 serializers.py라는 이름의 파일을 생성해준 뒤, 아래와 같은 코드를 작성한다.
from rest_framework import serializers
from polls.models import Question, Choice
class QuestionSerializer(serializers.Serializer):
# 각 필드들을 매핑시켜줌
id = serializers.IntegerField(read_only=True)
question_text = serializers.CharField(max_length=200)
pub_date = serializers.DateTimeField(read_only=True)
def create(self, validated_data):
return Question.objects.create(**validated_data)
def update(self, instance, validated_data):
# instance로 전달된 기존 Question 객체의 필드 값을 업데이트
# id와 pub_date는 read_only이므로 question_text만 update
instance.question_text = validated_data.get('question_text', instance.question_text)
instance.save()
return instance
QuestionSerializer라는 이름의 클래스를 생성해준 뒤, Question 모델이 가지고 있는 필드를 각각 serializers를 통해 매핑시켜주어야 한다. id값과 pub_date의 경우 자동 생성되는 항목이므로 read_only 옵션을 추가해준다.
그 다음 시리얼라이저에 대해서 생성(create)과 수정(update) 기능을 만들어준다. 생성의 경우 생성할 데이터만 받지만, 수정의 경우 수정 대상이 되는 인스턴스도 함께 인자로 받는다.
Django shell에서 serializer 사용하기
위에서 구현한 시리얼라이저를 django shell에서 사용해보자.
ModuleNotFoundError: No module named 'rest_framework' 에러가 발생할 경우 아래 접은 글을 참고
터미널 창에 'pip install djangorestframework' 입력해 설치
mysite/settings.py 내 INSTALLED_APPS에 'rest_framework' 추가
# objects 중 첫 번째 레코드로 실습
>>> from polls.models import *
>>> from polls_api.serializers import *
>>> q = Question.objects.first()
>>> q
<Question: [2024-10-07 04:20:27+00:00] 가장 추천하는 가을 캠핑장은 어디인가요?>
# 시리얼라이저 생성
>>> serializer = QuestionSerializer(q)
>>> serializer.data
{'id': 1, 'question_text': '가장 추천하는 가을 캠핑장은 어디인가요?', 'pub_date': '2024-10-07T04:20:27Z'}
# json으로 변환(serialize)을 위해 라이브러리 임포트
>>> from rest_framework.renderers import JSONRenderer
>>> json_str = JSONRenderer().render(serializer.data)
>>> json_str
b'{"id":1,"question_text":"\xea\xb0\x80\xec\x9e\xa5 \xec\xb6\x94\xec\xb2\x9c\xed\x95\x98\xeb\x8a\x94 \xea\xb0\x80\xec\x9d\x84 \xec\xba\xa0\xed\x95\x91\xec\x9e\xa5\xec\x9d\x80 \xec\x96\xb4\xeb\x94\x94\xec\x9d\xb8\xea\xb0\x80\xec\x9a\x94?","pub_date":"2024-10-07T04:20:27Z"}'
# json을 인스턴스로 변환(deserialize)하는 과정
>>> import json
>>> data = json.loads(json_str)
>>> data
{'id': 1, 'question_text': '가장 추천하는 가을 캠핑장은 어디인가요?', 'pub_date': '2024-10-07T04:20:27Z'}
위와 같은 과정으로 시리얼라이저를 이용해 Json으로 변환 및 인스턴스로 변환할 수 있다. 하지만 Deserialize의 경우 여기서 끝이 아니다. 다시 인스턴스로 변환한 데이터를 모델에 적용시켜주는 과정까지 마쳐야 한다.
# json에서 모델 인스턴스로 변환된 데이터를 인자로 받음
>>> serializer = QuestionSerializer(data=data)
# valid한 data인지 확인
>>> serializer.is_valid()
True
# 데이터 확인 (id와 pub_date는 read_only이므로 삭제)
>>> serializer.validated_data
{'question_text': '가장 추천하는 가을 캠핑장은 어디인가요?'}
# 데이터 저장(create 메서드 활용)
>>> serializer.save()
<Question: [2024-10-10 02:25:09.096995+00:00] 가장 추천하는 가을 캠핑장은 어디인
가요? (new)>
serializer를 통해 위에서 얻은 데이터를 모델에 create해주었다. 따로 create()라는 메서드를 사용한다고 표시하지는 않았는데, 어떻게 create 메서드가 실행된걸까?
serializer가 .save() 메서드를 사용할 때 받은 인자와 데이터 중복 여부를 따져 create 또는 update 메서드 중 어떤 것을 사용할지 판단해주기 때문이다. validated_data에는 question text만 담겨져 있어 이미 있는 질문이지만 id와 pub_date가 다르게 전달되고, instance가 따로 전달되지 않았기 때문에 create 메서드가 실행된 것이다.
>>> Question.objects.all()
<QuerySet [<Question: [2024-10-07 04:20:27+00:00] 가장 추천하는 가을 캠핑장은 어
디인가요?>, <Question: [2024-10-07 05:17:05.082114+00:00] 야구 vs 축구>, <Question: [2024-10-07 05:27:29.992184+00:00] abc???>, <Question: [2024-10-07 07:28:39.876305+00:00] 야구를 왜 좋아하시나요?>, <Question: [2024-10-08 04:34:08.922218+00:00] new_question>, <Question: [2024-10-10 02:25:09.096995+00:00] 가장 추천하는
가을 캠핑장은 어디인가요? (new)>]>
(new)표시가 붙은 '가장 추천하는 가을 캠핑장은 어디인가요?'라는 질문 레코드가 새로 생성된 것을 확인할 수 있다.
이제 update 메서드도 사용해 볼 차례이다. 새로 생긴 질문의 제목을 수정한다고 가정해보자.
# 최근 생성된 질문 변수로 선언
>>> new_question = Question.objects.last()
# 수정할 내용이 담긴 데이터
>>> data = {'question_text':'제목수정'}
# 수정 대상인 질문(instance)과 수정 내용 데이터를 인자로 serializer 생성
>>> serializer = QuestionSerializer(new_question, data=data)
# 데이터 확인
>>> serializer.is_valid()
True
>>> serializer.validated_data
{'question_text': '제목수정'}
# 업데이트
>>> serializer.save()
<Question: [2024-10-10 02:25:09.096995+00:00] 제목수정 (new)>
수정할 레코드와 수정 내용을 미리 선언해둔 뒤, 해당 변수들을 인자로 하는 serializer를 생성해주었다. 해당 형식의 인자를 2개 받는 메서드는 update이니, save()할 때 자동으로 update 메서드가 실행된다.
* 주의할 점
create 또는 update 메서드를 사용해 deserialize할 때, .validated_data 또는 .save()를 사용하기 위해서는 .is_valid()가 우선적으로 수행되어야 한다. 해당 데이터가 모델에 입력될 수 있는지를 판단하는 유효성 검증 단계이기 때문이다.
ModelSerializer 사용하기
위에서 사용한 방법보다 더 간단하게 시리얼라이저를 구현할 수 있는 방법이 있다. 바로 ModelSerializer를 사용하는 방법이다.
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = '__all__'
QuestionSerializer 클래스를 생성한 뒤 하단에 Meta 클래스를 또 한번 생성해준다. 이러면 이전처럼 필드를 일일히 매칭시켜줄 필요 없이, 모델명과 각각의 필드명을 리스트 형태로 반환 또는 '__all__'(전체)로 전달하면 된다.
또한 기본적으로 create()와 update() 메서드가 탑재되어 있기 때문에, 따로 해당 메서드를 작성해 줄 필요가 없다.
이 시리얼라이저를 사용해 레코드를 추가해보자. Django shell을 이용한다.
>>> from polls_api.serializers import *
>>> print(QuestionSerializer())
# read_only에 해당하는 값들을 자동으로 지정해준다.
QuestionSerializer():
id = IntegerField(label='ID', read_only=True)
question_text = CharField(label='질문', max_length=200)
pub_date = DateTimeField(label='생성일', read_only=True)
# create 메서드를 따로 지정해주지 않아도 자동으로 실행 가능하다.
>>> serializer = QuestionSerializer(data={'question_text':'모델 시리얼라이저로
생성'})
>>> serializer.is_valid()
True
>>> serializer.save()
<Question: [2024-10-10 04:20:19.022404+00:00] 모델 시리얼라이저로 생성 (new)>
'Minding's Programming > Django' 카테고리의 다른 글
[Django] 클래스 기반의 View, Mixin, Generic View (0) | 2024.10.10 |
---|---|
[Django] GET, POST, PUT, DELETE (1) | 2024.10.10 |
[Django] Admin 페이지 편집 (0) | 2024.10.10 |
[Django] 폼(Forms) (0) | 2024.10.08 |
[Django] 뷰(views)와 템플릿(templates) (0) | 2024.10.08 |