How to filter in Django Rest Framework function based view?

Viewed 1560

So many documentation for filtering in Django rest framework but all the examples are in class based view. but I am trying to do the same in DRF function based view. I wanted to do multiple filter for my items queryset.

I tried one way and it is working perfectly. Here first I am trying to search by item name or restaurant name in one request. then I take another keyword and try to filter restaurant name or item name based on restaurant city. It is working perfectly like if I hit this url http://localhost:8000/api/items/?keyword=lasagne&keyword1=paris

then it gives me the perfect response. But What I am asking for is that now my code looks for this specific part is messy and I want to add more fields for multiple filtering. Which procedure to follow? Should I follow this one and multiple requests and trying to filter from this.

Suppose now I want to filter the queryset based on dish_type, price, item_type, location and then search for items by name or restaurants by name

#this is my models

class Restaurant(models.Model):
    user = models.OneToOneField(CustomUser, related_name='restaurant', on_delete=models.CASCADE, null=False)
    name = models.CharField(max_length=200, blank=True, null=True)
    profile_picture = models.ImageField(null=True, blank=True)
    address = models.TextField(max_length=2000, blank=True, null=True)
    city = models.CharField(max_length=200)
    latitude = models.DecimalField(max_digits = 13, decimal_places = 7, blank=True, null=True)
    longitude = models.DecimalField(max_digits = 13, decimal_places = 7, blank=True, null=True)
    is_verified = models.BooleanField(default=False)
    createdAt = models.DateTimeField(auto_now_add=True)


    def __str__(self):
        return str(self.name)



class Item(models.Model):
    user = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
    name = models.CharField(max_length=220)
    image = models.ImageField(null=True, blank=True)
    dish_type = models.ForeignKey(Dishtype, on_delete=models.CASCADE)
    item_type = models.ForeignKey(Itemtype, on_delete=models.CASCADE)
    description = models.TextField(max_length=10000)
    rating = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True)
    numReviews = models.IntegerField(null=True, blank=True, default=0)
    old_price = models.DecimalField(max_digits=11, decimal_places=2)
    discount = models.IntegerField(blank=True, null=True)
    price = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True)
    countInStock = models.IntegerField(blank=True, null=True, default=0)
    createdAt = models.DateTimeField(auto_now_add=True)
    _id = models.AutoField(primary_key=True, editable=False)
    

    def save(self, *args, **kwargs):
        self.price = Decimal(self.old_price * (100 - self.discount) / 100)
        return super(Item, self).save(*args, **kwargs)
    

    class Meta:
        ordering = ['-createdAt']


    def __str__(self):
        return self.name

#serializer

class RestaurantSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField(read_only=True)
    
    class Meta:
        model = Restaurant
        fields = '__all__'

    
    def get_user(self, obj):
        user = obj.user
        serializer = UserSerializer(user, many=False)
        return serializer.data



class ItemSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField(read_only=True)
    dish_type = serializers.SerializerMethodField(read_only=True)
    item_type = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = Item
        fields = '__all__'

    def get_user(self, obj):
        user = obj.user
        serializer = RestaurantSerializer(user, many=False)
        return serializer.data

    def get_dish_type(self, obj):
        dish_type = obj.dish_type
        serializer = DishtypeSerializer(dish_type, many=False)
        return serializer.data

    def get_item_type(self, obj):
        item_type = obj.item_type
        serializer = ItemtypeSerializer(item_type, many=False)
        return serializer.data

#views.py

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getItems(request):
    user = request.user
    
    query = request.query_params.get('keyword')
    if query == None:
        query = ''

    cuery = request.query_params.get('keyword1')
    if cuery == None:
        cuery = ''
        items = Item.objects.select_related('user').select_related('dish_type').select_related('item_type').all().filter(
                    Q(name__icontains = query) | Q(user__name__icontains = query))
    else:
        restaurant_city = Item.objects.select_related('user').select_related('dish_type').select_related('item_type').all(
                            ).filter(Q(user__city__iexact = cuery))
        
        items = restaurant_city.filter(Q(name__icontains = query) | Q(user__name__icontains = query))


    serializer = ItemSerializer(items, many=True)
    return Response(serializer.data)

######Updated solved the problem

#filters.py

class ItemFilter(django_filters.FilterSet):
    numReviews = django_filters.NumberFilter()
    numReviews__gt = django_filters.NumberFilter(field_name='numReviews', lookup_expr='gt')
    numReviews__lt = django_filters.NumberFilter(field_name='numReviews', lookup_expr='lt')
    name = django_filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = Item
        fields = ['_id', 'dish_type__id']

#views

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getItems(request):
    user = request.user
    queryset = Item.objects.all()
    filterset = ItemFilter(request.GET, queryset=queryset)
    if filterset.is_valid():
         queryset = filterset.qs
    serializer = ItemSerializer(queryset, many=True)
    return Response(serializer.data)

now data are passing like this http://localhost:8000/api/items/?numReviews__gt=20&numReviews__lt=22

1 Answers

You can use queryset and override get_queryset function.

class FooViewSet(GenericViewSet, mixins.ListModelMixin):
    authentication_classes = [JSONWebTokenAuthentication]
    permission_classes = [IsAuthenticated]
    serializer_class = ItemSerializer
    def get_queryset(self):
        query = self.request.query_params.get('keyword', '')
        if not self.request.query_params.get('keyword1'):
            items = Item.objects.select_related('user').select_related('dish_type').select_related(
                'item_type').all().filter(
                Q(name__icontains=query) | Q(user__name__icontains=query))
        else:
            restaurant_city = Item.objects.select_related('user').select_related('dish_type').select_related(
                'item_type').all(
            ).filter(Q(user__city__iexact=self.request.query_params.get('keyword1', '')))
    
            items = restaurant_city.filter(Q(name__icontains=query) | Q(user__name__icontains=query))
        return items

Related