Udemy 강의를 들으면서, DRF 공식문서를 보면서, 그리고 구글링하면서 정리한 내용입니다.
Django REST Framework - Level One
Nested Relationships
ForeignKey를 이용해 두 테이블을 연결하는 방법을 알아보자. 장고에서 FK를 걸던 방식과 동일하다.
from django.db import models
# 추가
class Journalist(models.Model):
first_name = models.CharField(max_length = 60)
last_name = models.CharField(max_length = 60)
biography = models.TextField(blank = True)
def __str__(self):
return f'{self.first_name} {self.last_name}'
class Article(models.Model):
# ForeignKey 필드로 변경
author = models.ForeignKey(Journalist,
on_delete = models.CASCADE,
related_name = 'articles')
title = models.CharField(max_length = 120)
description = models.CharField(max_length = 200)
body = models.TextField()
location = models.CharField(max_length = 120)
publication_date = models.DateField()
active = models.BooleanField(default = True)
created_at = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
def __str__(self):
return f"{self.author} {self.title}"
Journalist 테이블 생성 후, Article 테이블 내 CharField였던 author 필드 속성을 ForeignKey로 바꿔주고 Journalist와 연결해준다.
Journalist 테이블의 1번에 해당하는 저자가 발행한 기사임을 확인할 수 있다. 이것을 좀 더 명확하게 표시할 수도 있다.
serializers.py에서 author 항목을 추가한다.
class ArticleSerializer(serializers.ModelSerializer):
time_since_publication = serializers.SerializerMethodField()
# 추가
author = serializers.StringRelatedField()
author 항목에 integer 말고 이름이 표시된다. models.py에 __str__
메소드를 이용해 firstname과 lastname이 출력되도록 지정했기 때문이다.
def __str__(self):
return f"{self.author} {self.title}"
출력되는 이름을 지정하지 않았다면 "Journalist object (1)"
이렇게 객체로 출력된다.
참조하는 테이블의 모든 필드 보기
author 이름만 출력하는 것 말고도 참고하는 테이블 행의 모든 값을 볼 수도 있다.
serializers.py에 JournalistSerializer 클래스를 추가하고, ArticleSerializer에 추가해준다.
# Journalist 테이블 데이터를 직렬화 할 클래스 추가
class JournalistSerializer(serializers.ModelSerializer):
class Meta:
model = Journalist
# 테이블 내 모든 필드 출력
fields = '__all__'
class ArticleSerializer(serializers.ModelSerializer):
time_since_publication = serializers.SerializerMethodField()
# author = serializers.StringRelatedField()에서 변경
author = JournalistSerializer(read_onle = True)
author Jane Doe에 대한 Journalist 테이블 내 모든 값이 출력된다.
반대로 Journalist api에서도 해당 journalist의 모든 Article을 볼 수도 있다. Journalist api를 생성하기 위해 serializers.py와 views.py, urls.py를 손봐준다.
먼저 serializers.py다. JournalistSerializer가 ArticleSerializer를 끌어와야 하므로 순서를 바꿔준다.
class ArticleSerializer(serializers.ModelSerializer):
time_since_publication = serializers.SerializerMethodField()
# 필드를 없애주지 않으면 'JournalistSerializer'가 정의되지 않았으므로 NameError가 발생한다.
#author = JournalistSerializer(read_onle = True)
'''
이하 ArticleSerializer 코드 생략
'''
class JournalistSerializer(serializers.ModelSerializer):
# 한 저자가 여러 article을 가질 수 있으므로 many = True 속성 추가
articles = ArticleSerializer(many = True, read_only = True)
class Meta:
model = Journalist
fields = '__all__'
다음은 views.py에서 JournalistListCreateAPIView 클래스를 만들어준다. 이전에 만들었던 ArticleListCreateAPIView 클래스와 뼈대는 같다.
class JournalistListCreateAPIView(APIView):
def get(self, request):
# 모든 저자를 불러올 것이므로 ORM은 .all()을 사용한다.
journalists = Journalist.objects.all()
serializer = JournalistSerializer(journalists, many = True)
return Response(serializer.data)
def post(self, request):
serializer = JournalistSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status = status.HTTP_201_CREATED)
return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)
urls.py에서 api url도 만들어준다.
urlpatterns = [
'''
이전 path 생략
'''
path('journalists/',
JournalistListCreateAPIView.as_view(),
name = 'journalist-list'
)
]
localhost:포트번호/api/journalists/
로 접속하면 아래처럼 journalist와 해당 journalist의 모든 article이 출력되는 것을 볼 수 있다.
하이퍼링크로 연결하기
HyperlinkedRelatedField를 이용하면 journalist의 article을 링크로 연결할 수도 있다. serializers.py와 views.py를 수정해준다.
먼저 serializers.py에서 articles 항목을 HyperlinkedRelatedField로 바꿔준다. view_name에는 urls.py에서 name으로 설정한 값을 넣어준다.
class JournalistSerializer(serializers.ModelSerializer):
articles = serializers.HyperlinkedRelatedField(many = True,
read_only = True,
view_name = 'article-detail')
class Meta:
model = Journalist
fields = '__all__'
views.py에는 context를 추가한다. context가 있어야만 article에 접근하는 절대(absolute) URL을 빌드할 수 있다.
class JournalistListCreateAPIView(APIView):
def get(self, request):
journalists = Journalist.objects.all()
# context 추가
serializer = JournalistSerializer(journalists,
many = True,
context = {'request' : request})
return Response(serializer.data)
def post(self, request):
serializer = JournalistSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status = status.HTTP_201_CREATED)
return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)
Json 형태로 함께 출력되던 article이 링크로 대체됐다. 이 링크를 클릭하면 해당하는 article 인스턴스의 세부 내용을 볼 수 있다.