Filter on multiple values in Django Rest Framework

9.9k Views Asked by At

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')
2

There are 2 best solutions below

2
On BEST ANSWER

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.

0
On

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)