노트

DRF 필터·검색·정렬

DRF Filtering, Searching, and Ordering

백엔드#django · 연결된 개념 4개

쉽게 말하면

DRF 필터·검색·정렬은 쇼핑 앱에서 '사이즈 M만', '셔츠 검색', '낮은 가격순'을 고르듯, 주소 뒤 파라미터로 목록을 좁히고 줄 세우는 장치예요. 서버는 원하는 것만 골라 보내 주죠.

비유가 깨지는 곳 화면에선 가벼워 보여도 SearchFilter의 부분 일치는 앞 와일드카드 LIKE라 데이터가 많으면 느려요. 본격 검색은 검색 엔진으로 옮기고, 정렬 허용 필드를 다 열면 숨은 값을 추측당할 수 있어요.

DRF의 목록 API는 쿼리 파라미터로 결과를 좁히는 세 가지 장치를 붙일 수 있다. 값이 정확히 맞는 것만 고르는 필터, 일부 문자열로 찾는 검색, 순서를 바꾸는 정렬이다. 모두 제네릭 뷰(GenericAPIView 계열)의 filter_backends로 적용된다.

가장 단순한 방법

class ReviewList(generics.ListAPIView):
    serializer_class = ReviewSerializer
 
    def get_queryset(self):
        qs = Review.objects.all()
        if user := self.request.query_params.get("user"):
            qs = qs.filter(author__username=user)
        return qs

규칙이 한두 개면 이걸로 충분하다.

백엔드 붙이기

from django_filters.rest_framework import DjangoFilterBackend
 
class WatchListView(generics.ListAPIView):
    queryset = WatchList.objects.all()
    serializer_class = WatchListSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["platform__name", "active"]   # ?platform__name=Netflix&active=true
    search_fields = ["title", "=platform__name"]      # ?search=dune  (=는 정확히 일치)
    ordering_fields = ["avg_rating", "created"]       # ?ordering=-avg_rating
  • DjangoFilterBackend(django-filter 패키지): 기본은 정확히 일치. 연관 모델 필드는 __로 따라간다. 범위·부분 일치가 필요하면 FilterSet 클래스를 정의한다. 예전 이름 filter_fields는 filterset_fields로 바뀌었다
  • SearchFilter: search_fields의 필드들에서 대소문자 무시(case-insensitive) 부분 일치(icontains)로 찾는다. 접두사 ^는 시작 일치, =는 정확히 일치
  • OrderingFilter: ?ordering=필드, 앞에 -면 내림차순. 허용할 필드는 ordering_fields로 정한다. 지정하지 않으면 시리얼라이저의 읽기 필드만 허용되고, "__all__"로 모든 모델 필드를 열면 응답에 없는 필드로 정렬해 그 값을 추측당할 수 있다

주의

  • SearchFilter의 부분 일치는 앞 와일드카드 LIKE라 데이터가 많으면 느리다. 본격적인 검색은 PostgreSQL 전문 검색(full-text search)이나 검색 엔진으로 옮긴다
  • 필터링 대상 컬럼에는 인덱스를 건다
  • 필터·정렬은 페이지네이션 (offset·cursor)과 함께 쓰이고, 커서 페이지네이션과 정렬을 같이 쓸 때는 정렬 필드를 제한한다

뷰 구조는 DRF 뷰 계층를 본다.

출처: DRF Filtering: Filtering against query parameters · DjangoFilterBackend · SearchFilter · OrderingFilter

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • DRF 시리얼라이저

    DRF(Django REST Framework)의 시리얼라이저는 모델 인스턴스·QuerySet을 JSON으로 바꿀 수 있는 파이썬 기본 자료형으로 바꾸고(직렬화, serialization), 반대로 들어온 데이터를 검증해 모델로 만드는(역직렬화, deserialization) 틀이다. 장고의 Form과 비슷하게 필드와 검증 규칙을 선언한다.

  • DRF 파서·렌더러와 콘텐츠 협상

    DRF에서 파서(Parser)는 요청 본문을 파이썬 자료형으로 바꾸고, 렌더러(Renderer)는 응답 데이터를 클라이언트가 받을 형식으로 바꾼다. 어떤 렌더러를 쓸지는 요청의 Accept 헤더를 보고 고르는데, 이를 콘텐츠 협상(content negotiation)이라 한다.

  • Django 모델 매니저와 QuerySet

    Django 모델 클래스는 DB 테이블에 대응하고, 모델의 매니저(Manager)가 그 테이블에 쿼리를 보내는 입구다. 기본 매니저 이름이 objects이고, 매니저가 돌려주는 QuerySet에 조건을 이어 붙여 쿼리를 만든다.

  • DRF API 테스트

    DRF는 장고 테스트 위에 API 요청을 편하게 보내는 APITestCase와 APIClient를 제공한다. 장고 테스트 러너(test runner)는 테스트용 DB를 따로 만들고, 각 테스트를 트랜잭션으로 감싸 끝나면 되돌리므로 실제 데이터를 건드리지 않는다.

  • DRF 인증과 권한

    DRF는 요청 처리를 두 단계로 나눈다. 인증 클래스(authentication class)는 요청을 보낸 사용자가 누구인지 식별해 request.user·request.auth를 채우기만 하고, 권한 클래스(permission class)가 그 사용자에게 이 요청을 허용할지 결정한다. 인증만으로는 요청이 막히지 않는다(authn-authz).

보기 옵션