pythondjangodjango-rest-frameworkdjango-filter

Django Rest Framework custom filter with default search and ordering filter


I have a project in Django Rest Framework where I need have endpoint where I'm able to search Document objects by title and text and possibility to search object is active and inactive, using to this URL address. I am using to achieve this Django_filters package. Example: https://localhost:8000/?is_active=True.

This is my model

class Document(models.Model):
    title = models.CharField(max_length=100)
    text = models.TextField()
    date = models.DateField()
    account = models.ForeignKey(
        to=Account,
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        related_name='documents',
        verbose_name='account',
        help_text='account',
    )
    is_active = models.BooleanField(default=True)

    def __str__(self):
        return self.title

Serializer

class DocumentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Document
        fields = ['id', 'title', 'text', 'date', 'account', 'is_active']

Custom FilterSet

class DocumentBackendFilter(dfilters.FilterSet):
    is_active = dfilters.BooleanFilter(field_name='is_active', lookup_expr='exact')

    class Meta:
        model = Document
        fields = ['is_active']

View

class DocumentsListView(viewsets.ModelViewSet):
    queryset = Document.objects.all()
    serializer_class = DocumentSerializer
    filterset_class = DocumentBackendFilter
    filterset_fields = ('is_active',)

    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['title', 'text']
    ordering_fields = ['title', 'text']

    def get_queryset(self):
        qs = super().get_queryset()
        qs = qs.filter(account__users=self.request.user)
        return qs

Problem:

Under url: http://127.0.0.1:8000/?is_active=True I have elements where is_active is set on True and False. Default search is working OK. How can I get search, ordering and filter objects based on is_active?


Solution

  • since you want to use the DocumentBackendFilter, you must add the DjangoFilterBackend from django_filters.rest_framework to the filter_backends list in your view class. Besides, If you set filterset_class, the view class will ignore the value list of filterset_fields, so you should provide one of them.

    class DocumentsListView(viewsets.ModelViewSet):
        # some code
        filterset_class = DocumentBackendFilter
        # filterset_fields = ('is_active',) -> remove this line
    
        filter_backends = [filters.SearchFilter, filters.OrderingFilter, DjangoFilterBackend]