Search code examples
django-rest-frameworkfilteringdjango-rest-viewsets

Filter on multiple values in Django Rest Framework


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

Solution

  • 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.