티스토리 뷰

DEV/Django

[Django DRF] Filter

뚜비두빱 2022. 5. 6. 15:20

DRF Filter

기본적인 viewsets class가 다음과 같이 되어 있을 경우

class IcecreamViewSet(viewsets.ModelViewSet):
    queryset = Icecream.objects.all()
    serializer_class = IcecreamSerializer

/api/icecream/ 으로 요청을 보내서 DB에 존재하는 icecream list를 불러오게 됩니다.

[
    {
        "id": 7,
        "name": "메로나",
        "price": 1000
    },
    {
        "id": 8,
        "name": "누가바",
        "price": 1000
    },
    {
        "id": 9,
        "name": "돼지바",
        "price": 1000
    },
...
]

/api/icecream/7/ 과 같이 요청을 보내면 해당 id값을 가진 하나의 데이터만을 불러오게 됩니다.

{
    "id": 7,
    "name": "메로나",
    "price": 1000
}

만약 name이 메로나 인것만 찾고 싶다면?

/api/icecream/?name=메로나 와 같이 쿼리 파라미터에 name이라는 key와 메로나라는 value를 넣어줘서 요청하면 됩니다.

하지만 기본적으로는 적용되어 있지 않아서 필터링이 가능하도록 만들어줘야 합니다.

간단하게는 다음과 같이 가능합니다.

class IcecreamViewSet(viewsets.ModelViewSet):
    queryset = Icecream.objects.all()
    serializer_class = IcecreamSerializer

    def get_queryset(self):
        queryset = Icecream.objects.all()
        name = self.request.query_params.get('name')
        price = self.request.query_params.get('price')
        if name is not None:
            queryset = queryset.filter(name=name)
        if price is not None:
            queryset = queryset.filter(price=price)
        return queryset

get_queryset에서 쿼리파라미터로 nameprice가 들어올 경우 필터링된 쿼리셋을 리턴합니다.

/api/icecream/?name=메로나&price=1000 으로 GET요청을 했을경우 다음과 같이 필터링 된 결과를 볼 수 있습니다.

[
    {
        "id": 1,
        "name": "메로나",
        "price": 1000
    },
    {
        "id": 2,
        "name": "메로나",
        "price": 1000
    },
    {
        "id": 3,
        "name": "메로나",
        "price": 1000
    },
...

DjangoFilterBackend

좀 더 세분화된 필터링을 하고싶을 경우, 그리고 좀 더 깔끔하게 만들고 싶을경우 FilterBackend를 이용하는것이 좋습니다.

DjangoFilterBackend 을 사용하려면 먼저  django-filter를 설치 해줘야 합니다

pip install django-filter

'django_filters' 를 INSTALLED_APPS에 추가 해줍니다

INSTALLED_APPS = [
    ...
    'django_filters',
    ...
]

다음과 같이 DjangoFilterBackend를 추가 해줍니다.

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}

또는 다음과 같이 일부 viewset에 각각 적용할 수도 있습니다.

from django_filters.rest_framework import DjangoFilterBackend

class IcecreamViewSet(viewsets.ModelViewSet):
    ...
    filter_backends = [DjangoFilterBackend]

위와 같이 설정을 마친뒤에 filterset_fields만 넣어주면 바로 필터링이 적용된 결과값을 확인할 수 있습니다.

class IcecreamViewSet(viewsets.ModelViewSet):
    queryset = Icecream.objects.all()
    serializer_class = IcecreamSerializer
    filterset_fields = ['name', 'price']

현재는 name, price필드만 필터링 가능하게 되어있고 적용하고싶은 모델의 필드명을 넣으면 됩니다. 만약 모든 필드를 적용하고 싶다면

필드 리스트 대신에‘__all__’을 넣어주면 모든 필드가 적용됩니다.

만약 필터를 밖으로 빼서 더 깔끔하게 하고싶다면 다음과 같이 filters.py를 만들고, 각각 모델의 필터를 클래스로 정의 해주는 방법으로도 사용이 가능합니다.

from app1.models import Icecream
import django_filters

class IcecreamFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(field_name='name')
    price = django_filters.NumberFilter(field_name='price')

    class Meta:
        model = Icecream
        fields = '__all__'
class IcecreamViewSet(viewsets.ModelViewSet):
    queryset = Icecream.objects.all()
    serializer_class = IcecreamSerializer
    filterset_class = IcecreamFilter # 하나만 추가

SearchFilter

문서를 보면 searchFilter도 확인해 볼 수 있습니다.

다음과 같이 두가지 속성만 넣어주면 바로 사용이 가능합니다.

filter_backends = [filters.SearchFilter]
search_fields = ['name', 'price']

127.0.0.1:8000/api/icecream/?search=메로나 와 같이 search를 쿼리 파라미터로 넣고 검색하면

(0.003) SELECT "app1_icecream"."id", "app1_icecream"."name", "app1_icecream"."price" FROM "app1_icecream" WHERE ("app1_icecream"."name" LIKE '%메로나%' ESCAPE '\\' OR "app1_icecream"."price" LIKE '%메로나%' ESCAPE '\\'); args=('%메로나%', '%메로나%'); alias=default

위와 같은 쿼리가 이뤄집니다. LIKE querynameprice에서 검색을 해줍니다.

만약 필드가 외래키로 연결이 되어있다면

search_fields = ['username', 'email', 'profile__profession']

과 같이 __로 연결 되어있는 모델의 속성에서까지 검색이 가능합니다.

다음과 같은 옵션들을 추가하여 검색도 가능합니다.

  • '^' Starts-with search.
  • '=' Exact matches.
  • '@' Full-text search. (Currently only supported Django's PostgreSQL backend.)
  • '$' Regex search.

그 외에 orderingFilter또한 존재합니다.

공식 사이트에서 더 자세하게 확인 가능합니다.

https://www.django-rest-framework.org/api-guide/filtering/#filtering

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함