Reputation: 174
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
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