blueFast
blueFast

Reputation: 44501

Create custom filter

Currently my view is as follows:

from rest_framework.permissions import AllowAny
from dynamic_rest.viewsets import DynamicModelViewSet
from django_filters.rest_framework import DjangoFilterBackend

from .models import Purchase
from .serializers import PurchaseSerializer


class PurchasesViewSet(DynamicModelViewSet):
    queryset = Purchase.objects.all()
    serializer_class = PurchaseSerializer
    permission_classes = (AllowAny,)
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('name', 'color')

Which allows me to filter by exact name and color.

My data has a date field (DateField type). I would like to create a custom filter by "quarter", so that this kind of request:

/purchases/?quarter=2018Q1

provides a list of objects with date field in the specified quarter. Note that quarter is not a model field.

What would the approach of creating such a custom filter?

Upvotes: 2

Views: 561

Answers (2)

JPG
JPG

Reputation: 88689

First, you have to create custom filter along with filter class

import django_filters
from rest_framework.exceptions import ValidationError


class QuarterFilter(django_filters.Filter): # Custom Filter
    def get_quarter_range(self, quarter):
        if quarter == 1:
            return [1, 3]
        elif quarter == 2:
            return [4, 6]
        elif quarter == 3:
            return [7, 9]
        elif quarter == 4:
            return [10, 12]
        else:
            raise ValidationError("quarter value must be range from 1-4")

    def filter(self, qs, value):
        """
        create your custom filtering logi here
        """
        # here the "value" will be the value parsed from URL params, ie "2018Q1"
        try:
            year, quarter = value.split("Q") # spliting the input to get year and quarter value
            qs = qs.filter(date__year=year)

            qs = qs.filter(date__month__range=self.get_quarter_range(quarter))
            return qs
        except:
            return qs


class PurchaseFilter(django_filters.FilterSet): # Custom Filter Class
    quarter = QuarterFilter()

    class Meta:
        model = Purchase
        fields = ['name', 'color', 'quarter']



Then, mention it in your view class with filterset_class attribute. Then your view be like,

class PurchasesViewSet(DynamicModelViewSet):
    queryset = Purchase.objects.all()
    serializer_class = PurchaseSerializer
    permission_classes = (AllowAny,)
    filter_backends = (DjangoFilterBackend,)
    # filter_fields = ('name', 'color') ---- Remove this line of code
    filterset_class = PurchaseFilter



NOTE
I'm not sure about this line,

qs = qs.filter(date__month__range=self.get_quarter_range(quarter))

But, this is how you need to do filtering in this particular case.

Hope this helps!!

Upvotes: 2

Ngoc Pham
Ngoc Pham

Reputation: 1450

you can create custom filter in filter_class

from rest_framework import filters

class CustomFilter(django_filters.rest_framework.FilterSet):
    class Meta:
        model = Purchase
        fields = ['name', 'color', 'quarter']
    quarter = QuarterFilter(name="quarter")

class QuarterFilter(django_filters.Filter):
    def filter(self, qs, value):
        # create custom in this with value
        return qs.filter(name=value)

class PurchasesViewSet(DynamicModelViewSet):
    queryset = Purchase.objects.all()
    serializer_class = PurchaseSerializer
    permission_classes = (AllowAny,)
    filter_backends = (DjangoFilterBackend,)
    filter_class = CustomFilter

Upvotes: 2

Related Questions