'How to add multiple filters when using Django Rest framework search_filter
I'm currently trying to create a fullstack website using django for the backend. One of the features I'm building is a search function. To do that, I used the built in django-rest SearchFilter, as well as the built in OrderingFilter so users can toggle how results are ordered. However, I also want users to be able to filter their results further, such as selecting a specific year, or a specific name, from a drowdown menu. So essentially, I want to be able to use a search filter and still specify another field that has to match exactly. For example, lets say the users searched for "Cat" and the results were as follows:
Name: Cat1
Description: A happy cat
Year: 2017
Name: Cat2
Description: A sad cat
Year: 2017
Name: Lion
Description: A large cat
Year: 2018
Name: Lion
Description: A large cat
Year: 2019
All of these results show up because they contain "cat" in either the name or description fields. But then, I want the user to be able to specify a year via a dropdown menu. So the menu would have 2017, 2018 and 2019 as options, and after selecting 2017, the results would be like this:
Name: Cat1
Description: A happy cat
Year: 2017
Name: Cat2
Description: A sad cat
Year: 2017
With the other years filtered out. I can't do this on the front end, because the database I'm working with has thousands of entries, meaning the results are returned in pages. This seems like a fairly straightforward problem, but none of the things I've tried have worked. Does anyone know the best way to approach this?
Here's the database model for the objects that are being searched:
class Measure(OverrideModel):
year = models.ForeignKey(Year, on_delete=models.PROTECT)
name = models.CharField(max_length=200)
description = models.TextField()
class Meta:
constraints = [
models.UniqueConstraint(
fields=["duration", "code"],
name=prefix("measure", "duration_code_uniq"),
)
]
And here is the current view I'm using:
class MeasureSearchViewSet(viewsets.ReadOnlyModelViewSet):
queryset = models.Measure.objects.all()
serializer_class = serializers.MeasureSerializer
filter_backends = [OrderingFilter, SearchFilter]
search_fields = ["name", "description"]
ordering_fields = ["duration", "name"]
def get_serializer(self, *args, **kwargs):
return super().get_serializer(
*args, program=self.program, tag=False, **kwargs
)
Any advice would be appreciated, thanks :)
Solution 1:[1]
You need to combine search and filter mechanisms. Apart from defining search_fieldsYou need to add filter_fields attribute to your ViewSet and add DjangoFilterBackend to filter_backends list:
class MeasureSearchViewSet(viewsets.ReadOnlyModelViewSet):
queryset = models.Measure.objects.all()
serializer_class = serializers.MeasureSerializer
filter_backends = [OrderingFilter, SearchFilter, DjangoFilterBackend]
search_fields = ["name", "description"]
ordering_fields = ["duration", "name"]
filterset_fields = ['year'] # enable filtering by year
def get_serializer(self, *args, **kwargs):
return super().get_serializer(
*args, program=self.program, tag=False, **kwargs
)
You can get more info at: https://www.django-rest-framework.org/api-guide/filtering/#generic-filtering
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
