There are entries added to a Django model and they look like:
"makes": [\"Ford\", \"Opel\", \"Mazda\", \"Toyota\", \"Volkswagen\"]
I was trying to filter out all entries containing a make, a list of makes or a partial name of a make, implementing custom filter:
from django_filters import BaseInFilter, CharFilter, FilterSet
from django_filters.rest_framework import DjangoFilterBackend
[...]
class ValueInFilter(BaseInFilter, CharFilter):
pass
class Value(FilterSet):
value__in = ValueInFilter(field_name='makes', lookup_expr='in')
class Meta:
model = Dealer
fields = '__all__'
class DealerViewSet(viewsets.ModelViewSet):
queryset = Dealer.objects.all()
serializer_class = DealerSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['type', 'city', 'makes', 'reputation']
Without custom filter, I'm only able to query something like /api/dealers/?makes=["Ford"]
to get results containing only Ford dealers. (1) How should I configure filter to strip brackets and quotation marks from the URL?
(2) I'd like to get also dealers selling Fords and other makes, like in:
makes = ["Ford", "Opel", "Mazda", "Toyota", "Volkswagen"]
"Ford" in makes
True
(3) Also, I'd love to be able to just type /api/dealers/?makes=f
and get Ford dealers, and Fiat dealers.
How to make it possible?
Using model designer's privilege, I rebuilt a bit the way the makes
were stored.
By applying ",".join(makes)
I got something like: makes = "Ford,Opel,Mazda,Toyota,Volkswagen"
(it's a single string; technically a CSV).
And now I'm able to search instead of filtering. Viewsets require adding the following lines:
from rest_framework import filters
[...]
filter_backends = [filters.SearchFilter]
search_fields = ['$makes']
The $
sign gives opportunity to perform RegEx searches, so querying /api/dealers/?search=f
will return all makes containing letter F (case insensitive). Still, filtering is also possible: /api/dealers/?city=Paris&search=f
would return all Fords, Fiats, etc. from Paris. In this specific case only searching for a make is possible. If one needs to extend searching to another fields, it has to be reflected in the search_fields
values.