본문 바로가기
Django/Django REST framework

4-1. Generic Views (GenericAPIView)

by hyun-am 2021. 6. 7.

Save and deletion hooks:

django의 일반적인 views는 일반적인 사용패턴의 shortcut으로 개발되었습니다. view 개발에서 발견되는 특정 공통 idioms와 패턴을 추출하여 사용자가 반복할 필요없이 데이터의 공통된 view를 빠르게 작성할 수 있도록 합니다.

CBV(Class Based views)의 주요 장점중 하나는 재사용 가능한 동작의 일부를 구성할 수 있는 방법입니다. DRF는 일반적으로 사용되는 패턴을 제공하는 여러개의 미리 작성된 views를 제공하여 이를 활용할 수 있습니다.

 

DRF에서 제공하는 일반적인 views를 사용하면 데이터베이스 모델에 가깝게 매핑되는 API View를 빠르게 작성할 수 있습니다.

 

일반적인 view가 API의 요구 사항에 맞지 않는 경우 일반 APIView 클래스를 사용하여 drop down하거나 일반적인 view에서 사용하는 mixins 및 기본 클래스를 재사용하여 가능한 generic views를 구성할 수 있습니다.

 

예시

일반적으로 generic view를 사용할 때 view를 오버라이드(재정의)하고 여러 클래스 속성을 설정합니다.

from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]

더 복잡한 경우에는 view class의 다양한 메서드를 재정의(오버라이드)할 수 있습니다. 예시는 다음과 같습니다.

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]

    def list(self, request):
        # Note the use of `get_queryset()` instead of `self.queryset`
        queryset = self.get_queryset()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

매우 간단한 경우 .as_view() 메서드를 사용하여 모든 클래스 속성을 전달할 수 있습니다. 예를 들어 url conf에는 다음과 같은 항목이 포함될 수 있습니다.

path('users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')

API Reference

GenericAPIView

이 클래스는 DRF의 APIview class를 확장하여 표준 목록 및 detail views에 일반적으로 필요한 동작을 추가합니다.

제공된 각각의 구체적인 generic views는 genericAPIView를 결합하여 구축됩니다. 하나 이상의 클래스가 mixin되어 있습니다.

Attributes

기본 세팅

다음 속성은 기본적인 view 동작을 제어합니다.

  • queryset : view에서 objects를 반환하는 데 사용해야 하는 쿼리셋 입니다. 일반적으로 이 속성을 설정하거나 get_queryset()메서드를 재정의해야 합니다. view 메서드를 재정의하는 경우 쿼리셋이 한 번 evaluated되고 이후 모든 request에 대해 캐시되므로 이 속성에 직접 액세스하는 대신 get_queryset()을 호출하는 것이 중요합니다.
  • serializer_class : 입력의 유효성 검사 및 역직렬화 및 출력 직렬화에 사용해야 하는 직렬화 클래스입니다. 일반적으로 이 속성을 정하거나 get_serializer_class()메서드를 재정의해야 합니다.
  • lookup_field : 개별 모델 인스턴스의 개체 조회를 수행하는 데 사용해야 하는 모델 필드입니다. 기본 값은 'pk'입니다. 하이퍼링크 API를 사용할 경우 사용자 지정 값을 사용해야 하는 경우 APIViewserilaizer class가 모두 룩업 필드를 설정해야 합니다.
  • lookup_url_kwarg : object lookup에 사용해야 하는 키워드 argument입니다. URL conf에는 이 값에 해당하는 키워드 argument가 포함되어야 합니다. 이 설정을 해제하면 lookup_field와 동일한 값을 사용하도록 기본값을 설정합니다.

페이지네이션 :

다음 속성은 list views와 함께 사용될 때 페이지네이션을 제어하는데 사용됩니다.

  • pagination_class : list의 결과값들을 페이징할 때 사용해야 하는 페이징 클래스입니다. 기본값은 DEFAULT_PAGINATION_CLASS 설정, 즉 'rest_framework.pagination.PageNumberPagination'입니다. pagination_class=None을 설정하면 view에서 페이지네이션이 비활성화 됩니다.

Filtering:

  • filter_backends : 쿼리셋을 필터링하는데 사용해야하는 filter backend 클래스 목록입니다. 기본값은 DEFAULT_FILTER_BACKENDS 설정과 동일한 값으로 설정됩니다.

Methods

Base methods:

get_queryset(self)

list view에 사용할 쿼리셋과 detail view의 lookup 기준으로 사용할 쿼리셋을 반환합니다. 기본적으로 쿼리셋 속성에서 지정한 쿼리 집합을 반홥합니다.

self.queryset은 한 번만 평가되고 그 결과는 이후의 모든 요정에 대해 캐시되므로 이 메서드는 항상 self.queryset에 직접 접근하지 않고 사용해야 합니다.

request를 수행하는 사용자와 관련된 쿼리셋 반환과 같은 동적 동작을 제공하도록 재정의 될 수 있습니다. 예시는 아래와 같습니다.

def get_queryset(self):
    user = self.request.user
    return user.accounts.all()

get_objects(self)

detail view에 사용할 개체 인스턴스를 반환합니다. 기본적으로 lookup_field 파라미터를 사용하여 기본 쿼리셋을 필터링 합니다.

둘 이상의 URL kwarg를 기반으로 하는 object lookups와 같은 보다 복잡한 동작을 제공하도록 재정의(오버라이드)될 수 있습니다.

def get_object(self):
    queryset = self.get_queryset()
    filter = {}
    for field in self.multiple_lookup_fields:
        filter[field] = self.kwargs[field]

    obj = get_object_or_404(queryset, **filter)
    self.check_object_permissions(self.request, obj)
    return obj

API에 개체 수준 권한이 없는 경우 선택적으로 self를 제외할 수 있습니다. check_object_dismissions를 확인하고 get_object_or_404 조회로부터 개체를 반환하기만 하면 됩니다.

 

filter_queryset(self,queryset)

쿼리셋이 지정되면 사용중인 필터 백엔드를 필터링하고 새 쿼리셋을 반환합니다.

예시코드는 다음과 같습니다.

def filter_queryset(self, queryset):
    filter_backends = [CategoryFilter]

    if 'geo_route' in self.request.query_params:
        filter_backends = [GeoRouteFilter, CategoryFilter]
    elif 'geo_point' in self.request.query_params:
        filter_backends = [GeoPointFilter, CategoryFilter]

    for backend in list(filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, view=self)

    return queryset

get_serializer_class(self)

serializer에 사용할 클래스를 반환합니다. 기본값은 serializer_class 특성을 반환하는 것입니다.

읽기 및 쓰기 작업에 다른 serializer을 사용하거나 다른 유형의 사용자에게 다른 serializer을 제공하는 등 동적 동작을 제공하도록 재정의될 수 있습니다.

예시코드는 다음과 같습니다.

def get_serializer_class(self):
    if self.request.user.is_staff:
        return FullAccountSerializer
    return BasicAccountSerializer

Save and deletion hooks:

  • perform_create(self,serializer) : 새로운 인스턴스를 저장할때 CreateModelMixin에 의해 호출됩니다.
  • perform_update(self,serializer) : 기존의 인스턴스를 새로 저장할때 UpdateModelMixin에 의해 호출됩니다.
  • perform_destroy(self, instance) : 기존의 인스턴스를 삭제할때 DestroyModelMixin에 의해 호출됩니다.

이러한 hook은 request에 내포되어 있지만 request data의 일부가 아닌 속성을 설정하는데 특히 유용합니다. 예를 들어, request user을 기준으로 또는 URL 키워드 argument를 기준으로 개체에 속성을 설정할 수 있습니다.

def perform_create(self, serializer):
    serializer.save(user=self.request.user)

또한 이러한 hook를 사용하여 validatoionError()를 제기하여 추가 검증을 제공할 수 있습니다. 이 기능은 데이터베이스 저장 시 적용할 validation logic이 필요한 경우에 유용할 수 있습니다. 예를 들면:

def perform_create(self, serializer):
    queryset = SignupRequest.objects.filter(user=self.request.user)
    if queryset.exists():
        raise ValidationError('You have already signed up')
    serializer.save(user=self.request.user)

다른 메서드:

GenericAPIView를 사용하여 view를 커스터마이징을 하는 경우 다음 메서드를 호출해야 할 수 있지만 일반적으로 다음 메서드를 재정의 할 필요는 없습니다.

  • get_serializer_context(self) : serializer에 제공해야 하는 추가 컨텍스트가 포함된 딕셔너리를 반환합니다. 기본적으로 'request', 'view' 및 'format'키를 포함합니다.
  • get_serializer(self, instance=None, data=None, many=False, partial=False) : serializer 인스턴스를 반환해 줍니다.
  • get_paginated_response(self, data) : 페이지네이션된 스타일 Response object를 반환합니다.
  • paginate_queryset(self, queryset) : 필요한 경우 페이지 object를 반환하거나 view에 대해 페이지네이션이 구성되지 않은 경우 none으로 쿼리셋을 페이지화 합니다.
  • filter_queryset(self, queryset) : 쿼리셋이 지정되면 사용중인 필터 백엔드로 필터링하고 새 쿼리를 반환합니다.

 

참고자료

링크 : https://www.django-rest-framework.org/api-guide/generic-views/#genericapiview

 

Generic views - Django REST framework

 

www.django-rest-framework.org

 

'Django > Django REST framework' 카테고리의 다른 글

5. ViewSets  (0) 2021.06.26
4-2 Generic Views (Mixin,Concrete)  (0) 2021.06.23
3. DRF-Views  (0) 2021.06.06
2. DRF-Response  (0) 2021.06.05
1. DRF-Requests  (0) 2021.05.30

댓글