Meme's IT

[Django] DRF(2) N:1 Relation 본문

BackEnd/Django

[Django] DRF(2) N:1 Relation

Memez 2023. 10. 19. 09:50

이번엔 게시판에 댓글다는 기능으로 DRF를 N:1 관계에서 어떻게 쓰는지 확인해보자

 


0. Serialize를 위해 SerializerModel만들어주기

# articles/serializers.py

from .models import Article, Comment

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'

 

 

1. GET - 모든 댓글 조회

(1) urls.py에서 url부터 추가해주기

# articles/views.py
urlpatterns = [
    ...
    path('comments/', views.comment_list),	# 추가
]

(2) view 함수 작성

# articles/views.py
from .models import Article, Comment
from .serializers import ArticleListSerializer, ArticleSerializer, CommentSerializer

@api_view(['GET'])
def comment_list(request):
    comments = Comment.objects.all()
    serializer = CommentSerializer(comments, many=True) # 다중데이터 → many=True
    return Response(serializer.data)

(3) POSTMAN으로 확인하기

      • http://127.0.0.1:8000/api/v1/comments/으로 확인
      • GET방식으로 바꿔주기

 

 

2. GET - 단일 댓글 조회

(1) 단일 댓글이므로 url부터 다시 만들기

# article/urls.py
urlpatterns = [
    ...
    path('comments/<int:comment_pk>/', views.comment_detail),
]

(2) view함수 작성

@api_view(['GET'])
def comment_detail(request,comment_pk):
    comment = Comment.objects.get(pk=comment_pk)
    serializer = CommentSerializer(comment)
    return Response(serializer.data)

(3) POSTMAN확인

  • http://127.0.0.1:8000/api/v1/comments/1/
  • GET 방식으로

 

 

3. POST - 단일 댓글 생성

(1) 단일 댓글도 article의 화면 → 댓글 생성이므로 새로운 url이 필요

urlpatterns = [
  	...
    path('article/<int:article_pk>/comments/',views.comment_create),
]

(2) view함수 작성

@api_view(['POST'])
def comment_create(request,article_pk):
    article = Article.objects.get(pk=article_pk)
    serializer = CommentSerializer(data=request.data)
    if serializer.is_valid(raise_exception=True):   # 예외가 발생되는것을 바로 처리해줌
        serializer.save(article=article)	# 위에서 가져온 article
        return Response(serializer.data, status=status.HTTP_201_CREATED)

(3) POSTMAN으로 확인하기

  • http://127.0.0.1:8000/api/v1/article/1/comments/ 으로 확인
  • body에 내용 넣어주기 / POST 방식으로
  • 근데 오류가 난다, 왜? valid검사하고 나서 → article 정보를 넣어주므로 valid 검사에서 걸리기 때문
  • 그럼 어떻게 해야 valid검사할 대는 빼고 나중에 넣어줄 수 있을까?
    • 이런 옵션을 '읽기 전용 필드'라고 한다
    • 읽기 전용 필드: ①유효성 검사에서 제외시키고  ②데이터 조회 시에는 출력 하는 필드
# articles/serializers.py

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = '__all__'
        read_only_fields = ('article',)	# 읽기전용필드 추가

 

 

4. DELETE & PUT - 단일 댓글 삭제 및 수정

 두 기능은 굳이 url추가할 필요 없음 → 댓글 삭제 페이지에서 동시에 가능

(1) 바로 view함수 수정

@api_view(['GET', 'DELETE', 'PUT'])
def comment_detail(request,comment_pk):
    comment = Comment.objects.get(pk=comment_pk)
    if request.method == 'GET':
        serializer = CommentSerializer(comment)
        return Response(serializer.data)
    elif request.method == 'DELETE':
        comment.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
    elif request.method == 'PUT':
        serializer = CommentSerializer(comment,data=request.data)   # partial필요 없음
        if serializer.is_valid(raise_exception=True):
            serializer.save()
            return Response(serializer.data)

(2) POSTMAN으로 확인

  • http://127.0.0.1:8000/api/v1/comments/20/
  • DELETE

  • http://127.0.0.1:8000/api/v1/comments/19/
  • POST방식, 수정할 데이터 입력


근데 여기서 댓글 조회할 때, article의 정보가 pk로 온다

확인하기 힘들지 않을까? 

게시글의 제목까지 제공하도록 하고 싶을 땐?

 

# 응답 데이터 재구성

# articles/serializers.py

class CommentSerializer(serializers.ModelSerializer):
    # Override 진행
    # 근데, 제목만 있는게 없네 → 새로 만들자
    class ArticleSerializer(serializers.ModelSerializer):
        class Meta:
            model = Article
            fields = ('title',)

    article = ArticleSerializer(read_only=True) # 읽기 전용 필드를 여기로 이사

    class Meta:
        model = Comment
        fields = '__all__'
        # read_only_fields = ('article',)

 

POSTMAN으로 제목이 조회되는 것을 확인할 수 있다.


# 역참조 데이터 구성

댓글 → 게시글을 조회할 때는 comment.article으로 조회할 수 있는데

게시글 → 댓글일 때는 어떻게 해야할까?

modelform을 사용할 때에는 article.comment_set으로 가능했었다

json에서는 역참조를 어떻게 해야할까?

  • 단일 게시글 조회시 해달 게시글에 작성된 댓글 목록 데이터 붙여서 응답
  • 단일 게시글 조회시 해당 게시글에 작성된 댓글 갯수 데이터도 함께 붙여서 응답

 

1. 단일 게시글 + 댓글 목록 출력

# articles/serializers.py

class ArticleSerializer(serializers.ModelSerializer):
    comment_set = CommentSerializer(many=True, read_only=True)
    # 다중데이터 - many=True, 읽기전용 - read_only=True

    class Meta:
        model = Article
        fields = '__all__'

이때, CommentSerializer를 가져오는 것이므로 CommentSerializer를 더 위쪽에 있도록 해야함

article에도 comment가 같이 나오는걸 확인할 수 있다

 

2. 단일 게시글 + 댓글 개수

댓글을 세어주는 필드가 새로 필요함

class ArticleSerializer(serializers.ModelSerializer):
    comment_set = CommentSerializer(many=True, read_only=True)
    # 새롭게 추가
    comment_count = serializers.IntegerField(source='comment_set.count', read_only=True)

    class Meta:
        model = Article
        fields = '__all__'

comment_count가 생긴 것을 확인할 수 있다.

 

▶ source 

  • 필드를 채우는 데에 사용할 속성의 이름
  • 점 표기법을 사용하여 속성을 탐색할 수 있음

▶주의사항

  • 특정 필드를 override하면 read_only_fields는 동작하지 않음
  • 해당 필드의 read_only 키워드 인자로 작성해야 함

 

 

 

'BackEnd > Django' 카테고리의 다른 글

[Django] API KEY 숨기는 방법  (0) 2023.10.27
[Django] API 문서화  (0) 2023.10.19
[Django] DRF(1) single model  (0) 2023.10.18
[Django] DRF란?  (0) 2023.10.18
[Django] RESTful API (2) 자원의 행위 / 표현  (0) 2023.10.18