partial improvements to search

This commit is contained in:
Sam
2021-03-02 13:17:37 +00:00
parent 5bab1d75cb
commit 1338570c05
2 changed files with 175 additions and 106 deletions

View File

@@ -535,6 +535,37 @@ class ProductSearchTest(TestCase):
# check prices # check prices
self.assertTrue(payload['prices']['min'] <= payload['prices']['max']) self.assertTrue(payload['prices']['min'] <= payload['prices']['max'])
def test_anon_user_can_search_no_querystring(self):
expected_instances = [
self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes"),
self.factory(tags="colores/rojos, tono/brillante"),
self.factory(tags="lunares/azules", description="zapatos rojos"),
self.factory(tags="lunares/rojos", description="zapatos"),
self.factory(attributes='"zapatos de campo", tono/oscuro'),
]
unexpected_instances = [
self.factory(description="chanclas"),
self.factory(tags="azules"),
]
q = quote("zapatos rojos")
url = f"{self.endpoint}?q="
# send in request
response = self.client.get(url)
# check response
self.assertEqual(response.status_code, 200)
# load response data
payload = response.json()
# check for expected fields in payload
self.assertIsNotNone(payload.get('filters'))
self.assertIsNotNone(payload.get('count'))
self.assertIsNotNone(payload.get('products'))
self.assertIsNotNone(payload.get('prices'))
# check for object creation
self.assertEquals(len(payload['products']), len(expected_instances) + len(unexpected_instances))
def test_anon_user_can_paginate_search(self): def test_anon_user_can_paginate_search(self):
expected_instances = [ expected_instances = [
self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes"), self.factory(tags="lunares/rojos", category='zapatos', description="zapatos verdes"),
@@ -549,10 +580,10 @@ class ProductSearchTest(TestCase):
] ]
q = quote("zapatos rojos") q = quote("zapatos rojos")
limit = 2
# test limit less than available
limit = 3
url = f"{self.endpoint}?q={q}&limit={limit}" url = f"{self.endpoint}?q={q}&limit={limit}"
# send in request
response = self.client.get(url) response = self.client.get(url)
# check response # check response
@@ -562,6 +593,44 @@ class ProductSearchTest(TestCase):
self.assertEquals(len(payload['products']), limit) self.assertEquals(len(payload['products']), limit)
self.assertEquals(payload['count'], len(expected_instances)) self.assertEquals(payload['count'], len(expected_instances))
# test limit less than available
limit = 10
url = f"{self.endpoint}?q={q}&limit={limit}"
response = self.client.get(url)
# check response
self.assertEqual(response.status_code, 200)
# load response data
payload = response.json()
self.assertEquals(len(payload['products']), len(expected_instances))
self.assertEquals(payload['count'], len(expected_instances))
# test limit equal to available, offset zero
limit = len(expected_instances)
offset = 0
url = f"{self.endpoint}?q={q}&limit={limit}&offset={offset}"
response = self.client.get(url)
# check response
self.assertEqual(response.status_code, 200)
# load response data
payload = response.json()
self.assertEquals(len(payload['products']), len(expected_instances))
self.assertEquals(payload['count'], len(expected_instances))
# test limit and offset equal to available
limit = len(expected_instances)
offset = limit
url = f"{self.endpoint}?q={q}&limit={limit}&offset={offset}"
response = self.client.get(url)
# check response
self.assertEqual(response.status_code, 200)
# load response data
payload = response.json()
self.assertEquals(len(payload['products']), 0)
self.assertEquals(payload['count'], len(expected_instances))
def test_anon_user_can_filter_shipping_cost_true(self): def test_anon_user_can_filter_shipping_cost_true(self):
expected_instances = [ expected_instances = [
self.factory(tags="colores/rojos, tono/brillante", shipping_cost=100.00), self.factory(tags="colores/rojos, tono/brillante", shipping_cost=100.00),
@@ -685,7 +754,6 @@ class ProductSearchTest(TestCase):
] ]
q = quote("zapatos rojos") q = quote("zapatos rojos")
# discount=true
url = f"{self.endpoint}?q={q}&category=ropa/nueva" url = f"{self.endpoint}?q={q}&category=ropa/nueva"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
@@ -815,7 +883,7 @@ class ProductSearchTest(TestCase):
url = f"{self.endpoint}?q={q}&order=oldest" url = f"{self.endpoint}?q={q}&order=oldest"
# send in request # send in request
response = self.client.get(url) response = self.client.get(url)
import ipdb; ipdb.set_trace()
# check response # check response
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
# load response data # load response data

View File

@@ -141,12 +141,7 @@ def product_search(request):
if q is None: if q is None:
return Response({"errors": {"details": "No query string to parse"}}) return Response({"errors": {"details": "No query string to parse"}})
elif q is '':
# return everything
serializer = ProductSerializer(Product.objects.all(), many=True)
products = serializer.data
# filters = extract_search_filters(products)
return Response(data={"filters": [], "count": len(products), "products": products})
try: try:
# we collect our results here # we collect our results here
result_set = set() result_set = set()
@@ -156,49 +151,55 @@ def product_search(request):
'max': None, 'max': None,
} }
if q == '':
# filter entire queryset
products_qs = Product.objects.all()
if tags:
products_qs = Product.objects.filter(tags=tags)
if category:
products_qs = Product.objects.filter(category=category)
# serialize and list data
serializer = ProductSerializer(products_qs, many=True)
result_list = [dict(i) for i in serializer.data]
else:
# split query string into single words # split query string into single words
chunks = q.split(' ') chunks = q.split(' ')
for chunk in chunks: for chunk in chunks:
product_set, min_price, max_price = find_related_products_v6(chunk, shipping_cost, discount, category, tags, price_min, price_max) product_set, min_price, max_price = find_related_products_v6(chunk, shipping_cost, discount, category, tags, price_min, price_max)
# update price values # update price values
if product_set: if product_set:
# import ipdb; ipdb.set_trace()
if prices['min'] is None or min_price['price__min'] < prices['min']: if prices['min'] is None or min_price['price__min'] < prices['min']:
prices['min'] = min_price['price__min'] prices['min'] = min_price['price__min']
if prices['max'] is None or max_price['price__max'] > prices['max']: if prices['max'] is None or max_price['price__max'] > prices['max']:
prices['max'] = max_price['price__max'] prices['max'] = max_price['price__max']
# add to result set # add to result set
result_set.update(product_set) result_set.update(product_set)
# TODO: add search for entire phrase ??? # serialize and list data
serializer = SearchResultSerializer(product_set, many=True)
result_list = [dict(i) for i in serializer.data]
# extract filters from result_set # extract filters from result_set
filters = extract_search_filters(result_set) filters = extract_search_filters(result_set)
# order the results
result_list = list(result_set)
if order == 'newest': if order == 'newest':
# order results by created # order results by created
ordered_products = sorted(result_list, key= lambda x:x.created, reverse=True) result_list = sorted(result_list, key= lambda x:x['created'], reverse=True)
elif order == 'oldest': elif order == 'oldest':
# order results by created # order results by created
ordered_products = sorted(result_list, key= lambda x:x.created, reverse=False) result_list = sorted(result_list, key= lambda x:x['created'], reverse=False)
else: elif q != '':
# order results by RANK # order results by RANK
ordered_products = sorted(result_list, key= lambda rank:rank.rank, reverse=True) result_list = sorted(result_list, key= lambda x:x['rank'], reverse=True)
# extract max and min price values
serializer = SearchResultSerializer(ordered_products, many=True)
product_results = [dict(i) for i in serializer.data]
total_results = len(product_results)
total_results = len(result_list)
# RESULTS PAGINATION # RESULTS PAGINATION
if limit is not None and offset is not None: if limit is not None and offset is not None:
limit = int(limit) limit = int(limit)
offset = int(offset) offset = int(offset)
product_results = product_results[offset:(limit+offset)] result_list = result_list[offset:(limit+offset)]
elif limit is not None: elif limit is not None:
limit = int(limit) limit = int(limit)
product_results = product_results[:limit] result_list = result_list[:limit]
return Response(data={"filters": filters, "count": total_results, "products": result_list, 'prices': prices})
return Response(data={"filters": filters, "count": total_results, "products": product_results, 'prices': prices})
except Exception as e: except Exception as e:
return Response({"errors": {"details": str(e)}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return Response({"errors": {"details": str(e)}}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)