이전 사례에서 Serializer를 만들 때, 각 필드를 하나하나 정의해 주었다. 마치 모델을 다시 한 번 작성하는 것 같은 불편함이 있었다. 이 문제를 해결해 주는 것이 ModelSerializer이다.
ModelSerializer는 크게 아래와 같은 3가지 기능을 제공한다. 주는 편리함이 워낙 크기에 Base Serializer보다 훨씬 생산성을 높일 수 있다.
본 사례에서는 아래와 같은 순서로 코드를 작성하였다.
1) class Meta 작성
__all__
, exclude, 직접 명시 ('id', 'name')2) serializer로 정의해 줘야 되는 필드
class JournalistSerializer(serializers.ModelSerializer):
class Meta:
model = Journalist
fields = '__all__'
class ArticleSerializer(serializers.ModelSerializer):
time_since_publication = serializers.SerializerMethodField()
class Meta:
model = Article
fields = "__all__" # Article 모델의 모든 필드 시리얼라이즈
def get_time_since_publication(self, object):
publication_date = object.publication_date
now = datetime.now(timezone.utc) # 에러 해결. timezone 임포트한 뒤 추가
time_delta = timesince(publication_date, now)
return time_delta
datetime.now(timezone.utc)을 timzezone.now()로 바꾼 이유
https://it-eldorado.tistory.com/13 -> Aware 객체를 이용하기 위해서
앞써 언급했듯이 ForeignKey 필드를 사용하고자 할 때, 기본적으로 아무런 설정이 없으면 참조하고 있는 pk 값을 가져온다. 만약 pk 값 외에 다른 값을 가져오고 싶다면, 아래와 같은 메소드를 이용할 수 있다.
__str__
메소드에서 정의한 string를 리턴class ArticleSerializer(serializers.ModelSerializer):
...
author = serializers.StringRelatedField()
[API 호출 결과]
[내 API 호출 결과]
Journalist 모델 def __str__(self):
에서 first_name과 last_name을 결합해 준 string이다.
[models.py]
class Journalist(models.Model):
...
def __str__(self):
return f"{ self.first_name } { self.last_name }"
class JournalistSerializer(serializers.ModelSerializer):
...
# articles = ArticleSerializer(many=True, read_only=True)
class ArticleSerializer(serializers.ModelSerializer):
...
author = JounalistSerializer(read_only=True)
(
[API 호출 결과]
[내 API 호출 결과]
이 필드는 Read only로만 사용된다. 비슷한 역할을 하는 모듈로 PrimaryKeyRelatedField가 있는데, 이 모듈은 타겟 모델의 primary key 값을 가져오게 된다.
[코드]
[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)
[API 호출 결과]
[내 API 호출 결과]
Serializer에 queryset 혹은 instance 외에 추가로 정보를 전달하고 싶을 때에는 context를 이용해서 전달할 수 있다. 앞의 사례에서는 request란 key값으로 request object를 전달한 경우이다.
이를 Debug하여 자세히 어떤 데이터들이 담겨있는지 살펴보면 아래 그림과 같다.