Filter on multiple values in Django Rest Framework
Asked Answered
P

2

5

I have a model that I want to filter on multiple values.

my model:

class Product(models.Model):
    ean = models.CharField(max_length=13, unique=True)
    product_id = models.CharField(max_length=20, null=True, blank=True)
    product_image = models.URLField(max_length=300, null=True, blank=True)
    product_title = models.CharField(max_length=300, null=True, blank=True)

I either want to filter on the 'ean' field, or on the primary key, both will work. With my current set up, I only see the last value. For example, when I construct the URL as www.example.com/api/Product/?id=1&id=2, I only get see the product with id 2, and I want to see product with id 1 and with id 2.

How should I construct my ViewSet? Currently I have:

class ProductViewSet(ModelViewSet):
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer
    filter_backends = [DjangoFilterBackend]
    filter_fields  = ('id','ean')
Paleo answered 26/11, 2020 at 10:23 Comment(2)
Use filterset class which will give you more control over filtering operationsSidney
Could you maybe give an example @ArakkalAbu?Paleo
U
29

There is an even simpler way to achieve this using the django-filter package. Deep within the django-filter documentation, it mentions that you can use "a dictionary of field names mapped to a list of lookups".

Your code would be updated like so:

# views.py

from django_filters.rest_framework import DjangoFilterBackend

class ProductViewSet(ModelViewSet):
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = {
        'id': ["in", "exact"], # note the 'in' field
        'ean': ["exact"]
    }

Now in the URL you would add __in to the filter before supplying your list of parameters and it would work as you expect:

www.example.com/api/Product/?id__in=1,2

The django-filter documentation on what lookup filters are available is quite poor, but the in lookup filter is mentioned in the Django documentation itself.

Ufo answered 30/6, 2021 at 18:30 Comment(2)
filterset_fields instead of filter_fields worked for meFluecure
hard to find this in the documentation, thanks!Silassilastic
R
1

You can try something like this in your views.py and pass your keys id and ean in params. Notice that you have to pass the multiple values as comma separated values in params.

class ProductViewSet(APIView):
    def get(self, request):
        _id   = self.request.GET.get('id', None).split(',')
        ean   = self.request.GET.get('ean', None).split(',')

        qs = Product.objects.filter(Q(id__in=_id) | Q(ean__in=ean))
        data = serializers.ProductSerializer(qs, many=True, context={'request': request}).data

        if data:
                return Response({
                        'message': 'success',
                        "data":data,
                    },status=200)
            else:
                return Response({
                        'message':'no data available',
                        'success':'False'
                    },status=200)
Ruminate answered 26/11, 2020 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.