코드로 우주평화

Generic views - Methods 본문

나는 이렇게 본다/Django REST framework

Generic views - Methods

daco2020 2022. 2. 15. 15:44

*이 글은 DRF 공식문서를 보고 개인적으로 번역한 글입니다. 전문적인 번역이 아니므로 내용이 틀릴 수 있습니다.

 

 

 

 

Generic views - Methods

 

Base methods:

get_queryset(self)

이 메서드는 리스트 뷰, 디테일 뷰의 조회를 위해 사용되는 쿼리셋을 반환한다.

queryset의 지정된 속성에 따라 반환되는 것이 기본값이다.

self.queryset 보다 이 매서드를 사용해야한다. self.queryset 은 결과를 이후 모든 리퀘스트에 캐시되기 때문이다.

유저의 리퀘스트에 따른 쿼리셋 반환처럼 다양한 요청에 응답하기 위해 오버라이드할 수도 있다.

 

 

For example:

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

 

만약 generic view에서 serializer_class를 사용한다면 n+1과 같은 문제를 해결하기 위해 이 메서드에서select_related와  prefetch_related 를 이용해 퀴리셋을 최적화 할 수 있다.

 

n+1 문제와 언급된 방법의 사례는 django documentation의 관련 섹션을 참조하라.

 

 

 

 

 

get_object(self)

이 메서드는 디테일 뷰에서 사용하기 위해 객체 인스턴스를 반환한다.

기본 쿼리셋을 필터링하기 위해 lookup_field 파라미터를 사용하는 것이 기본값이다.

둘 이상의 URL kwarg를 조회하는 것과 같이 복잡한 작업을 수행하기 위해 오버라이드 할 수 있다.

For example:

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_permissions 을 제외하고get_object_or_404 을 통해 객체를 간단히 반환할 수 있다.

 

 

 

 

filter_queryset(self, queryset)

쿼리셋을 넣으면 사용 중인 어느 백엔드 필터든 그것을 필터링하여 새 쿼리셋을 반환한다.

For example:

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 속성을 반환한다.

다른 serializers를 사용하거나 다른 사용자에게 serializers를 제공하는 것과 같이 다양한 작업을 수행하기 위해 오버라이드 할 수 있다.

 

 

For example:

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

 

Save and deletion hooks:

다음 메서드는 mixin 클래스에서 제공하며, 객체 저장 또는 삭제 동작을 쉽게 오버라이드할 수 있도록 한다.

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

 

이러한 훅은 리퀘스트 ‘데이터의 일부’가 아닌 리퀘스트 ‘속성’을 설정하는 데 유용하다.

예를 들어, ‘리퀘스트 유저’ 또는 ‘URL 키워드 인수’를 이용해 객체의 속성을 설정할 수 있다.

(*훅은 ‘걸다’의 의미로 여기서는 ‘부가 설정’이라고 생각하자.)

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

 

이러한 오버라이드 지점들은 객체를 저장하기 전, 후에 발생하는 동작을 추가하는 데 유용하다.
(예를들어 확인 이메일 발송, 업데이트 기록 )

 

def perform_update(self, serializer):
    instance = serializer.save()
    send_email_confirmation(user=self.request.user, modified=instance)

 

 

이러한 훅을 사용하여 ValidationError()를 발생시켜 유효성 검사를 추가할 수도 있다.

이는 데이터베이스 저장 시점에 적용하면 유용하다. 예를 들어 :

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'를 사용하면서 커스텀을 하고 싶은 경우 불러올 수 있다.

  • get_serializer_context(self) - serializer에 주어야 하는 추가 컨텍스트가 포함된 딕셔너리를 반환. 기본적으로 ''요청'', ''보기'' 및 ''형식'' 키를 포함한다.
  • get_serializer(self, instance=None, data=None, many=False, partial=False) - serializer 인스턴스를 반환.
  • get_paginated_response(self, data) - 페이지를 매긴 'Response' 객체를 반환.
  • paginate_queryset(self, queryset) - 필요한 경우 쿼리셋에 페이지를 매기고, 페이지 개체를 반환. 만약 이 뷰에 대해 페이지 나누기가 설정되지 않은 경우 'None'을 반환.
  • filter_queryset(self, queryset) - 쿼리셋을 넣으면 사용 중인 필터 백엔드로 필터링하여 새 쿼리셋을 반환.

'나는 이렇게 본다 > Django REST framework' 카테고리의 다른 글

Generic views - Attributes  (0) 2022.02.14
Function Based Views  (0) 2022.02.11
Class-based Views  (0) 2022.02.10