How do I use multi tag filters in Django REST Framework API response?

first of all I apologize if I did not ask a question using better words. I am building a DRF App, I have Products Model, ProductSerializer and ProductsSummaryView. Furthermore, I have Workspace Model (not going to talk about it as it is not related to the issue). Now, I want to return those products details in success response which are attached with a specific Workspace, filtered on some parameters.

What I have done: I defined filterset_fields and filter_backends. It works fine. For example, if I go to this URL {{domain}}/path/?country__title=Japan, it filters the data for Japan and show me. But the problem is, I want to filter using multi-tag, such as let's say if I want to see details for Japan and Korea, so I want something like this {{domain}}/path/?country__title=Japan&country__title=Korea, but it is not working and it just returns all the details. I even tried adding empty list format in the URL and tried this URL {{domain}}/path/?country__title[]=Japan&country__title[]=Korea, but it still did not work.

Can anybody help me in this?

My Product Model is:

class Product(BaseModel):
    """Product model to store all prices of a product and
    related brand and countries it's available in"""
    product = models.CharField(max_length=255)
    country = models.ForeignKey(Country, null=True, on_delete=models.DO_NOTHING)
    car_brand = models.ForeignKey(
        CarBrand, on_delete=models.DO_NOTHING, null=True, blank=True
    )
    part = models.ForeignKey(Part, null=True, blank=True, on_delete=models.DO_NOTHING)
    fzg_segment = models.ForeignKey(
        FZGSegment, on_delete=models.DO_NOTHING, null=True, blank=True
    )
    parts_group = models.ForeignKey(
        PartsGroup, on_delete=models.DO_NOTHING, null=True, blank=True
    )
    last_collected = models.DateField(null=True, blank=True)
    usage_recommendation = models.CharField(max_length=255)
    recommended_action = models.CharField(max_length=255)
    recommended_action_value = models.DecimalField(max_digits=6, decimal_places=2)
    recommended_price = models.DecimalField(max_digits=6, decimal_places=2)
    rrp = models.DecimalField(max_digits=6, decimal_places=2)
    iam_price = models.DecimalField(max_digits=6, decimal_places=2)
    currency = models.ForeignKey(
        Currency, null=True, blank=True, on_delete=models.DO_NOTHING
    )
    iam_index = models.DecimalField(max_digits=6, decimal_places=2)
    factor = models.DecimalField(max_digits=6, decimal_places=2)
    items_count = models.PositiveIntegerField(default=0)
    manufacturer = models.ForeignKey(
        Manufacturer, on_delete=models.DO_NOTHING, null=True, blank=True
    )
    is_in_stock = models.BooleanField(default=True)
    added_at = models.DateField(null=True, blank=True)
    last_in_stock = models.DateField(null=True, blank=True)
    last_searched_at = models.DateField(null=True, blank=True)
    avg_in_stock = models.DecimalField(
        null=True, blank=True, max_digits=6, decimal_places=2
    )

    def __str__(self):
        return self.product

My ProductSerializer Serializer is:

class ProductSerializer(serializers.ModelSerializer):
    """Serializer for the part object"""
    parts_group = PartsGroupSerializer()
    fzg_segment = FZGSegmentSerializer()

    class Meta:
        model = Product
        fields = (
            "id",
            "product",
            "fzg_segment",
            "parts_group",
            "last_collected",
            "usage_recommendation",
            "recommended_action",
            "recommended_action_value",
            "recommended_price",
            "rrp",
            "iam_price",
            "iam_index",
            "factor",
            "items_count",
        )
        read_only_fields = ("id",)

And my ProductsSummaryView API is:

class ProductsSummaryView(mixins.ListModelMixin, viewsets.GenericViewSet):
    """Viewset to return data for products in a workspace"""
    serializer_class = serializers.ProductSerializer
    permission_classes = (permissions.IsWorkspaceAdminPermission,)
    pagination_class = StandardSetPagination
    filter_backends = [DjangoFilterBackend]
    filterset_fields = [
        "fzg_segment__title",
        "parts_group__title",
        "car_brand__title",
        "usage_recommendation",
        "recommended_action",
    ]

    def get_queryset(self) -> models.Product:
        """Returns queryset of all the products of a workspace"""
        workspace = self.kwargs["workspace"]
        workspace = get_object_or_404(models.Workspace, pk=workspace)
        return workspace.products.all()

Can anyone help me and let me know what do I need to do in order to achieve desired functionality?

To filter a queryset based on multiple values for a particular field in Django Rest Framework (DRF), you can use the in lookup type in your filterset. To use this lookup type, you will need to update your filterset fields to include the in lookup as follows:

class ProductFilter(filters.FilterSet):
    country__title = filters.CharFilter(field_name='country__title', lookup_expr='in')
    
    class Meta:
        model = Product
        fields = ['country__title']

With this filterset, you can then use the in lookup type in your URL query parameters to filter the queryset based on multiple values. For example, to filter the queryset for products with countries titled "Japan" and "Korea", you can use the following URL:

{{domain}}/path/?country__title__in=Japan,Korea

Alternatively, you can also use the MultipleChoiceFilter provided by Django-filter in your filterset to allow filtering on multiple values for a particular field.

class ProductFilter(filters.FilterSet):
    country__title = filters.MultipleChoiceFilter(field_name='country__title')
    
    class Meta:
        model = Product
        fields = ['country__title']

With this filterset, you can then use the following URL to filter the queryset for products with countries titled "Japan" and "Korea":

{{domain}}/path/?country__title=Japan&country__title=Korea

You need to use BaseInFilter, example:

from django_filters.filters import BaseInFilter
from django_filters import rest_framework as filters

class CharInFilter(BaseInFilter, filters.CharFilter):
    pass


class ProductFilterSet(filters.FilterSet):
    country = CharInFilter(field_name="country__title", lookup_expr='in')

    class Meta:
        model = Product
        fields = ["country"]
    

The params url like: /?country=Japan,Korea

Back to Top