DRF ListAPIView, RetrieveAPIView

guswls·2022년 8월 13일
0

DRF 시리즈

목록 보기
5/5
post-thumbnail

이 포스트는 인프런의 "Django REST Framework 핵심사항"강의를 듣고 제작하였습니다.

이번 글에서는 저번 글에서 다뤘던 개념에서 더 나아가 코드를 직접 보면서 GenericView들 중 일부에 대해 어떻게 활용하는 지에 대해서 간단하게 다뤄보려고 한다.

본격적인 시작전에 우선 우리가 사용할 URL과 그 URL에 사용할 View를 생각을 해놔야 한다.

일단 우리가 만들 웹사이트는 블로그의 형식이고 이에 따라서 글의 리스트페이지, 글의 상세페이지, 댓글 작성 등을 할 수 있어야된다.


1. ListAPIView 와 RetrieveAPIView


View의 이름에서 알 수 있듯이 queryset의 리스트를 보여주는 것이 ListAPIView이고 그 중 하나의 인스턴스에 대해서만 보여줄 때 사용하는 것이 RetrieveAPIView이다.

이에 대해서 한번 알아보도록 하자.


2. urls.py

우선은 글의 리스트를 보여주는 페이지와 글의 상세페이지를 보여주는 페이지를 구현하기 위해서는 각각의 URL들에 대해서 GenericView들을 매칭시켜주어야 한다.

다음과 같이 urls.py에서 각각의 URL과 그에 따른 View를 작성해주자.

#api2 > urls.py

from django.urls import path, include
from api2 import views


urlpatterns = [
    path('post/',views.PostListAPIView.as_view(),name='post-list'),
    path('post/<int:pk>',views.PostRetrieveAPIView.as_view(),name='post-detail'),
]
  1. as_view()메소드에 대한 설명은 이 글에 자세히 나와있으니 자세한 설명은 생략한다.
    쉽게 말해서 Class형 View를 사용하기 위한 진입메소드라고 생각하면 된다.

  2. DRF에서는 url-name과 관련된 기본 규칙이 있다.
    꼭 아래의 규칙을 지킬 필요는 없지만 url-name은 해당 url의 동작을 유추할 수 있는 단어로 짓는 것이 좋다. ViewSet + router의 조합을 사용한다면 자동적으로 아래의 규칙에 따라 url-name이 정의되고 동작 시 사용된다.

DRF의 url-name 규칙

{ model 명 } - list : pk가 없는 기본 url ex ) post/
{ model 명 } - detail : pk를 사용하는 url ex ) post/1/


3. views.py

바로 코드부터 확인해보도록 하자.

#api2 > views.py

from rest_framework.generics import ListAPIView, RetrieveAPIView, CreateAPIView 
from api2.serializers import PostSerializer, CommentSerializer
from blog.models import Post, Comment


class PostListAPIView(ListAPIView):
    queryset=Post.objects.all()
    serializer_class=PostSerializer

class PostRetrieveAPIView(RetrieveAPIView):
    queryset=Post.objects.all()
    serializer_class=PostSerializer

urls.py에서 각각 url과 대응시킨 view들에 대한 코드들이다. 매우 간결한 것을 알 수 있는데 이것이 바로 GenericView의 장점이라고 할 수 있을 것이다. 기본 제공하는 기능만 사용한다면 이렇게만 작성해도 완성이다.

각각 ListAPIViewRetrieveAPIView를 상속받아 만들어졌으며 querysetserilalizer_class가 정의
된 것을 확인할 수 있다. 이 두 개에 대한 정보는 반드시 있어야된다.

GenericView의 간단한 동작흐름을 살펴보면 다음과 같다.

db로부터 데이터들을 가져옴 -> 그 데이터serializer -> serializer데이터를 반환

즉, queryset = db로부터 가져온 data들, serializer_class = serializer 방법 / 형식으로 이해하면 된다.

코드를 살펴보기전에 간략하게 ListAPIViewRetrieveAPIView에 대해서 알아보려고 한다.


4. ListAPIView와 RetrieveAPIView의 비교

저번 글에서 소개했던 것과 같이 cdrf.comDRF에 존재하는 클래스들의 정보들이 잘 정리되어있어 이를 활용해도 된다. 이 글에서는 파일을 직접 접근해서 ListAPIViewRetrieveAPIView의 차이점에 대해서 알아보려고 한다.

ListAPIView의 list

#rest_framework > mixins.py

class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

		#페이지에 관한 부분
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

RetrieveAPIView의 retrieve

#rest_framework > mixins.py

class RetrieveModelMixin:
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

각각의 Mixin클래스에서 list()retrieve()메소드들을 확인할 수 있다.

이를 통해 알 수 있는 차이점은 다음과 같다.

list와 retrieve의 차이점

list( )retrieve( )
queryset을 가져오는 메소드filter_querysetget_object
serializer의 인자many = TrueDefault ( many = False )
  • queryset : listqueryset전체에 대해서 가져오고 retrievequeryset인스턴스 하나에 대해서만 가져온다.

  • get_serializer : listmany=True로 지정하여 queryset전체의 serilaizer된 값을 반환하지만
    retrieve하나의 인스턴스에 대해서만 serializer된 데이터를 반환한다.


    get_objectget_serlializer의 동작방식에 대해서는 GenericAPIView에서 찾아볼 수 있다.

이러한 차이점으로 인해 ListAPIViewRetrieveAPIView이 각각 다른 동작을 하는 것이라고 생각하면 된다.


5. serializers.py

serializer에 관한 이야기가 많이 나오고 있는데 쉽게 생각하면 사용자에게 정보를 보여줄 출력포맷을 정하는 것으로 이해할 수 있다.

코드와 함께 살펴보자.

#api2 > serializers.py

from rest_framework import serializers
from blog.models import Post, Comment

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'title', 'image', 'like', 'category']

PostSerializerModelSerializer클래스를 상속받아 만들어졌으며 클래스의 내용은 일단 Meta클래스로 정의했다. Serializer는 상황에 따라 더욱 세분화하여 나타낼 수도 있으며 이에 대해서는 다음에 자세히 다뤄보도록 하겠다.

이렇게 urls.py, views.py, serializers.py를 정의하고 나면 대략적인 구현이 끝났다고 보면 된다. 이제 서버를 실행시켜보도록 하자.


6. 서버 실행

이제 서버를 실행해서 우리가 작성했던 구현했던 API에 대한 URL에 접속해서 살펴보자.

사진과 같이 post/ 접근하면 이렇게 DB에 저장되었던 post에 대한 정보가 리스트로 잘 출력되는 것을 알 수 있다.

그리고 post/1/로 접근하면 이렇게 idpk가 서로 같은 하나의 인스턴스가 출력되는 것을 확인할 수 있다.

7. 총정리

  1. ListAPIViewqueryset에 대한 리스트를, RetrieveAPIView는 그 중 하나의 인스턴스를 사용자에게 반환한다.

  2. 이 두 GenericView가 다르게 동작하는 이유는 상속받은 Mixin클래스에서의 동작방식이 다르기 때문이다.
profile
안녕하세요

0개의 댓글