I have a tagging system in place for a model that my API exposes. The models look something like this:
class TaggableModel(models.Model):
name = models.CharField(max_length=255)
tags = models.ManyToManyField(Tag, related_name="taggable_models")
class Tag(models.Model):
tag = models.CharField(max_length=32)
I've then set up a serializer and view that look like:
class TaggableModelSerializer(serializers.ModelSerializer):
class Meta:
model = TaggableModel
fields = ('id', 'name', 'tags',)
read_only_fields = ('id',)
class TaggableModelViewSet(viewsets.ModelViewSet):
queryset = TaggableModel.objects.all()
serializer_class = TaggableModelSerializer
permission_classes = (AllowAny,)
filter_backend = [DjangoFilterBackend]
filterset_fields = ['tags']
If I want to grab all TaggableModels
that have tag ids 1, 2, or 3, I can do so via:
https://my-api-domain/api/taggable-models?tags=1&tags=2&tags=3
Is there a way to split on a delimiter, so I can pass it all as one parameter? e.g.:
https://my-api-domain/api/taggable-models?tags=1,2,3
It looks like I can write my own custom DjangoFilterBackend filters, but I am a bit unsure as to where to start. Or perhaps there is an easier way to accomplish this?
Sure you can do this by having custom filterset class with specific field 'widget' (that's how it is called in django-filters)
Here's a sample you can try:
# filters.py
from django_filters.rest_framework import FilterSet, filters
from django_filters.widgets import CSVWidget
from .your_models import Tag, TaggableModel
class TaggableModelFilterSet(FilterSet):
tags = filters.ModelMultipleChoiceFilter(
queryset=Tag.objects.all(), widget=CSVWidget,
help_text=_("A list of ids, comma separated, identifying tags"),
method='filter_tags'
)
class Meta:
model = TaggableModel
fields = ['tags']
def filter_tags(self, queryset, name, value):
if value:
queryset = queryset.filter(tags__in=value)
return queryset
# views.py
class TaggableModelViewSet(viewsets.ModelViewSet):
queryset = TaggableModel.objects.all()
serializer_class = TaggableModelSerializer
permission_classes = (AllowAny,)
filter_backends = [DjangoFilterBackend]
filter_class = TaggableModelFilterSet