8

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
  • Use filterset class which will give you more control over filtering operations Commented Nov 26, 2020 at 10:31
  • Could you maybe give an example @ArakkalAbu? Commented Nov 26, 2020 at 10:39

2 Answers 2

31

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.

Sign up to request clarification or add additional context in comments.

2 Comments

filterset_fields instead of filter_fields worked for me
This is the correct answer, but I really wish the OP had desired something like ?product_title__contains=stove&product_title__contains=oven, so that legitimate multiple values were used. Instead, we work around the multivalue issue with the in lookup expression.
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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.