Arishta
Arishta

Reputation: 174

Django is ignoring filters

I am trying to create a simple "Search" feature for my e-commerce website project which has several products in its database.

models.py

    INR='₹'
    USD='$'
    CURRENCY_LIST=[(INR,'INR'),(USD,'USD')]
    subcategory=models.ForeignKey(Subcategory,on_delete=models.CASCADE)
    category=models.ForeignKey(Category,on_delete=models.CASCADE)
    name=models.CharField(max_length=50)
    price=models.DecimalField(max_digits=8,decimal_places=2,db_column='price')
    currency=models.CharField(max_length=3,choices=CURRENCY_LIST,default=INR,db_column='currency')
    view_count=models.IntegerField(default=0)
    @property
    def combined(self):
        return self.price+self.currency

    class Meta:
        db_table='Products'
        verbose_name_plural='products'
    def __str__(self):
        return self.name    

serializers.py

    class Meta:
        model=Products
        fields='__all__'
views.py
    def get(self,request):
        if request.method=="GET":
            search=request.query_params['search']
            sort=request.query_params['sort']
            start,end=request.query_params['filter'].split('-')
            q1=Products.objects.filter(name__icontains=search)
            q2=Products.objects.filter(subcategory__name__icontains=search)
            q3=Products.objects.filter(category__name__icontains=search)
            q1=q1.union(q2,q3)
            if sort=="low to high":
                q1=q1.filter(price__gte=start,price__lte=end).order_by('name','price')
                serializer=ProductsSerializer(q1,many=True)
                return JsonResponse({"response":serializer.data})
            elif sort=="high to low":
                q1=q1.filter(price__gte=start,price__lte=end).order_by('-price','name')
                return JsonResponse({"response":serializer.data})               
            elif sort=="most popular":
                q1=q1.filter(price__gte=start,price__lte=end).order_by('views')
                return JsonResponse({"response":serializer.data})

Before the second 'if' block starts(in views.py file), I am getting correct search results. But after that, Django simply returns the same unfiltered queryset.

Here is the outcome for print(q1.query).

(SELECT `Products`.`id`, `Products`.`subcategory_id`, `Products`.`category_id`, `Products`.`name`, `Products`.`price`, `Products`.`currency`, `Products`.`view_count` FROM `Products` WHERE `Products`.`name` LIKE %shirt%) UNION (SELECT `Products`.`id`, `Products`.`subcategory_id`, `Products`.`category_id`, `Products`.`name`, `Products`.`price`, `Products`.`currency`, `Products`.`view_count` FROM `Products` INNER JOIN `Subcategory` ON (`Products`.`subcategory_id` = `Subcategory`.`id`) WHERE `Subcategory`.`name` LIKE %shirt%) UNION (SELECT `Products`.`id`, `Products`.`subcategory_id`, `Products`.`category_id`, `Products`.`name`, `Products`.`price`, `Products`.`currency`, `Products`.`view_count` FROM `Products` INNER JOIN `Category` ON (`Products`.`category_id` = `Category`.`id`) WHERE `Category`.`name` LIKE %shirt%) ORDER BY (4) ASC, (5) ASC

Upvotes: 1

Views: 201

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477160

First of all, it is probably better to use a single queryset here, like:

from django.db.models import Q
from decimal import Decimal

search=request.query_params['search']
sort=request.query_params['sort']
start,end=request.query_params['filter'].split('-')

q1 = Products.objects.filter(
    Q(name__icontains=search) |
    Q(subcategory__name__icontains=search) |
    Q(category__name__icontains=search)
).filter(price__gte=Decimal(start),price__lte=Decimal(end))

Next you can let the search parameter decide how to order the items, like:

if sort == 'low to high':
    q1 = q1.order_by('price', 'name')
elif sort == 'high to low':
    q1 = q1.order_by('-price', 'name')               
elif sort == 'most popular':
    q1 = q1.order_by('views')

Finally you serialize and return the response:

serializer = ProductsSerializer(q1,many=True)
return JsonResponse({'response': serializer.data})

Upvotes: 2

Related Questions