Django의 generic views는 일반적인 사용 패턴에 대한 지름길로 개발했습니다. view 개발에서 발견된 특정 공통 관용구와 패턴을 취하고 이를 추상화하여 반복할 필요 없이 데이터의 공통 view를 빠르게 작성할 수 있습니다.
-Django Documentation
class-bassed views의 주요 이점 중 하나는 재사용 가능한 동작을 구성할 수 있습니다. REST framework는 일반적으로 사용되는 패턴을 제공하는 사전 구축된 여러 보기를 제공함으로써 이를 활용합니다.
REST framework에서 제공하는 generic views를 이용하면 database models에 밀접하게 매핑되는 API views를 빠르게 구축할 수 있습니다.
generic views가 API의 요구 사항과 적합하지 않은 경우 일반 APIview class를 사용하도록 drop down하거나 mixins와 base classes를 조립해서 generic views를 만들 수 있습니다.
Examples
일반 view를 사용할 때 view를 override하고 여러 class 속성을 설정합니다.
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 `get_queryset()`를 사용하세요 `self.queryset`대신에
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
간단한 경우에 .as_view() method를 사용하여 class에 속성을 전달하고 싶을 수도 있습니다. URLconf에 이렇게 포함 될 수 있습니다.
# 미쳤네..진짜 간단하네..
path('users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
API Reference
GenericAPIView
이 class는 REST framework's APIView를 extends하여 일반적으로 필요한 list와 detail views를 추가합니다.
제공된 각각의 generic views는 GenericAPIView와 하나 이상의 mixin classes와 결합됩니다.
Attributes
Basic settings:
아래의 속성들은 basic view를 제어합니다
- queryset - 이 view에서 객체를 반환하는데 사용해야 하는 쿼리 셋트입니다. 일반적으로 이 속성을 설정하거나 get_queryset() method를 override 해야 합니다. view 메서드를 overriding 하면 이 속성에 직접 액세스 하는 대신 get_queryset()을 호출하는 것이 중요합니다. queryset은 한번 평가 되고 다음의 request에 캐시되기 때문입니다.
- serializer_class serializer class는 input 유효성을 검사하며 역직렬화하고 output을 직렬화하는데 사용해야 하는 직렬 변환기 class 입니다. 일반적으로 이 속성을 설정하거나 get_serializer_class() 메서드를 재정의해야 합니다.
- lookup_field - 개별 모델 instance의 object를 조회를 수행하는데 사용해야하는 model field 입니다. 기본값은 'pk'입니다. 하이퍼링크된 API를 사용할때 사용자 정의 값을 사용해야 하는 경우 API 보기와 serializer classes의 설정을 했는지 확인해야 합니다.
- lookup_url_kwarg object 조회에 사용해야하는 URL 키워드 인수입니다. URL conf에는 이 값에 해당하는 키워드 argument가 포함되야 합니다. 설정하지 않으면 기본적으로 lookup_field와 동일한 값을 사용합니다.
Pagination
다음 속성은 list views를 사용할 때 pagination을 제어할 때 사용됩니다.
- pagination_class - list 결과에 페이지를 매길 때 사용해야 하는 pagination class 입니다. 기본 값은 DEFAULT_PAGENATION_CLASS 설정과 동일한 값인 'rest_framework.pagination.PageNumberPagination' 입니다. pagination_class=None으로 설정 시 pagination이 비활성화됩니다.
Filtering
- filter_backends - queryset을 필터링하는데 사용해야 하는 필터 백엔드 클래스 목록입니다. 기본 값은 DEFAULT_FILTER_BACKENDS setting과 동일한 값입니다.
Methods
Base methods:
get_queryset(self)
list views에 사용되어야하고 detail views에서 조회 시 기초로 사용되어야 하는 queryset을 반환합니다.
기본적으로 queryset attribute에 지정된 queryset을 반환합니다.
self.queryset은 한번만 평가되고, 해당 결과는 다음 requests에 캐시되므로 직접 액세스하는 대신 항상 이 메서드를 사용해야 합니다.
사용자에게 특정한 queryset 반환과 동적 동작을 제공하기 위해 재정의 될 수 있습니다.
def get_queryset(self):
user = self.request.user
return user.accounts.all()
Note: generic view에 사용된 serializer_class가 orm 관계에 있어 n+1 문제가 발생하는경우, select_related와 prefetch_related를 사용하여 이 방법에서 queryset을 최적화 할 수 있습니다. n+1 문제에 대한 자세한 정보와 언급된 method에 대해 사용 사례를 보려면 django 문서의 관련 섹션을 참조하세요.
get_object(self)
detail views에 사용해야 하는 객체 인스턴스를 반환합니다. base queryset을 반환하기 위해 lookup_field parameter을 사용하는 것이 기본값입니다.
둘 이상의 URL kwarg를 기반으로 한 조회와 같은 보다 복잡한 동작을 제공하기 위해 override 가능합니다
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
Note: API에 object level permissions이 포함되지 않은 경우 선택적으로 self.check_object_permissions를 제외하고 간단히 get_objects_or_404 조회에서 개체를 반환할 수 있습니다.
filter_queryset(self, queryset)
queryset이 주어지면 사용 중인 백엔드로 filtering하여 새 쿼리를 반환합니다.
def filter_queryset(self, queryset):
filter_backends = [CategoryFilter]
if 'geo_route' is self.request.query_params:
filter_backends = [GeoRoutFilter, CategoryFilter]
elif 'geo_point' is 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에 사용해야 하는 class를 반환합니다. serializer_class 속성을 반환하는 것이 기본값 입니다.
아래와 같이 재정의 될 수 있습니다.
def get_serializer_class(self):
if self.request.user.is_staff:
return FullAccountSerializer
return BasicAccountSerializer
저장 및 삭제 hooks:
다음 methods들은 mixin class에서 제공되며 객체 저장 또는 삭제 동작을 쉽게 재정의 할 수 있습니다.
- perform_create(self, serializer) Called By CreateModleMixin 새로운 object instance를 저장할 때
- perform_update(self, serializer) Called By UpdateModelMixin 기존 object instance에 저장할 때
- perform_destroy(self, serializer) Called by DestroyModelMixin 객체 object instance를 삭제할 때
이러한 hooks들은 request에 함축되어 있는 data의 속성을 설정하는데 특히 유용합니다. 예를 들어 request user 또는 URL keyword 인수를 기반으로 object의 속성을 설정할 수 있습니다.
def perform_create(self, serializer):
serializer.save(user=self.request.user)
이러한 override point는 object 저장 전후에 발생하는 이메일을 보내거나 업데이트를 기록하는 동작을 추가하는데 특히 유용합니다
def perform_update(self, serializer):
instance = serializer.save()
send_email_confirmation(user=self.request.user, modified=instance)
또한 이러한 hooks를 사용하여 ValidationError()를 발생시켜 추가 유효성 검사를 제공할 수도 있습니다. 이는 db의 저장 시점에 적용할 유효성 검사가 필요한 경우 유용하게 사용됩니다.
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)
other methods:
GenericAPIView를 이용 시 호출해야 할 수도 있지만 일반적으로 다음 메서드를 override 할 필요하는 없습니다.
- get_serializer_context(self) - serializer에 제공되어야 하는 추가 context가 포함된 사전을 반환, default값은 'request', 'view', 'format' key를 포함합니다.
- get_serializer(self, instance=None, data=None, many=False, partial=False) serializer instance를 반환합니다.
- get_paginated_response(self, data) - 페이지네이션이 적용된 Response object를 반환합니다.
- paginate_queryset(self, queryset) - 필요한 경우 queryset에 page를 매기고 page object를 반환하거나 pagenation이 구성되지 않은 경우 None을 반환합니다.
- filter_queryset(self, queryset) - queryset이 주어지면 사용 중인 filter backends로 필터링하여 새 쿼리 세트를 반환합니다.
Mixins
mixin class는 기본 view의 기능을 제공합니다. mixin class는 .get(), .post()와 같은 handler methods를 직정 정의하는 대신 action methods를 제공합니다. 이를 통해 보다 유연하게 구성할 수 있습니다.
rest_framework.mixins에서 import 할 수 있습니다.
ListModelMixin
queryset listing을 구현하는 .list(request, *args, **kwargs) method를 제공합니다. queryset이 채워지면 response로 200 OK를 return 합니다. reseponse data는 옵션으로 paginated가 가능합니다.
CreateModelMixin
새로운 model instance를 creating과 saving하는 .create(request, *args, **kwargs)method를 제공합니다.
object가 생성되면 객체의 serialized된 object를 response의 body를 사용해 201 Created response를 반환합니다.
representation에 url이라는 key가 포함되어 있으면 응답의 Location header가 해당 값으로 채워집니다.
객체 생성을 위해 제공된 request data가 유효하지 않은 경우 400 Bad Request response가 reseponse body에 return 될 것입니다.
RetrieveModelMixin
response에서 기존 model instance를 return 하는 .retrieve(request, *args, **kwargs)
object를 검색할 수 있는 경우 object의 serialized 된 표현을 response body에 200 OK를 return하고 그렇지 않으면 404 Not Found를 return 합니다.
UpdateModelMixin
model instance를 update 및 save을 구현하는 .update(request, *args, **kwargs) method를 제공합니다.
또한 update에 대한 모든 필드가 선택 사항이라는 점을 제외하면 업데이트 method와 유사한 .partial_update(request, *args, **kwargs) method를 제공합니다. 이를 통해 HTTP PATCH 요청을 지원할 수 있습니다.
object가 업데이트 되면 object의 serialized된 response를 body로 사용하여 200 OK를 return 합니다.
만약 request data가 유효하지 않으면 400 Bad Request response가 body에 error 세부정부와 함께 return 됩니다.
DestroyModelMixin
기존 model instance를 삭제를 구현하는 .destroy(request, *args, **kwargs) method를 제공합니다.
object가 삭제되면 204 No Content 응답이, 그렇지 않다면 404 Not Found가 반환됩니다.
Concrete View Classes
generic view를 사용하는 경우 크게 customize가 필요하지 않는 한 일반적으로 이 수준에서 작업할 것입니다.
view class는 rest_framework.generics에서 가져올 수 있습니다.
CreatAPIView
create 전용 endpoint에 사용됩니다. post method handler을 제공합니다.
Extends: GenericAPIView, CreateModelMixin
ListAPIView
read-only 전용으로 사용되는 model instance의 모음입니다. get method handler을 제공합니다.
확장: GenericAPIView, ListModelMixin
RetrieveAPIView
read-only 전용으로 단일 Model instance를 나타냅니다. get method를 제공합니다.
Extends: GenericAPIView, RetrieveModelMixin
DestroyAPIView
delete-only method로 단일 Model instance에 사용됩니다. delete method를 제공합니다
Extends: GenericAPIView, DestroyModelMixin
UpdateAPIView
update-only 전용으로 단일 model instance를 나타냅니다. put과 patch method를 제공합니다
Extends: GenericAPIView, UpdateModelMixin
ListCreateAPIView
Model instance를 read-write에 사용됩니다. get과 post method를 제공합니다.
extends: GenericAPIView, ListModelMixin, CreateModelMixin
RetrieveUpdateAPIView
단일 Model instance를 read or update에 사용됩니다
get, put, patch method를 제공합니다
Extends: GenericAPIView, RetrieveModelMixin, UpdateModelMixin
RetreiveDestroyAPIView
단일 Model instance를 read or delete에 사용됩니다
get, delete method를 제공합니다.
Extends: GenericAPIView, RetrieveModelMixin, DestroyModelMixin
RetrieveUpdateDestroyAPIView
단일 Model instacne를 read-write-delete에 사용됩니다
get, put, patch, delete method를 제공합니다
Customizing the generic views
Customizing the generic views
종종 일반적인 generic views를 사용하지만 얏간의 customized를 하고 싶을 것이다. 여러 곳에서 customized된 동작을 일부 재사용하려면 해당 동작을 공통 class로 refactoring하여 필요에 따라 view나 viewset에 적용 할 수 있습니다.
Creating custom mixins
class MultipleFieldLookupMixin:
'''
여러 필드의 필터링을 얻으려면 default single field filtering 대신 이 mixin을 적용하세요
'lookup_fields' 속성을 base로 합니다
'''
def get_object(self):
queryset = self.get_queryset() # 기존 base queryset
queryset = self.filter_queryset(queryset) # backends filter 적용
filter = {}
for field in self.lookup_fields:
if self.kwargs.get(field):
filter[field] = self.kwargs[field]
obj = get_objects_or_404(queryset, **filter)
self.check_object_permissions(self.request, obj)
return obj
그 뒤 사용자 정의 동작을 적용해야 할 때 언제든지 이 mixin을 view나 viewset에 적용할 수 있습니다.
class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_fields = ['account', 'username']
Creating custom base classes
여러 view에서 mixin을 사용하는 경우 한 단계 더 나아가 프로젝트 전체에 사용할 수 있는 고유한 기본 view set을 생성할 수 있습니다.
class BaseRetrieveView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
pass
class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,generics.RetrieveUpdateDestroyAPIView):
pass
'Django > restframework' 카테고리의 다른 글
Routers (0) | 2024.01.23 |
---|---|
Viewsets (2) | 2024.01.22 |
DRF docs API Guide Class-based Views (1) | 2024.01.15 |
DRF docs API Guide Responses (0) | 2024.01.12 |
DRF docs API Guide Request (0) | 2024.01.09 |