mirror of
				https://github.com/magnum-opus-tender-hack/backend.git
				synced 2025-10-31 23:07:26 +03:00 
			
		
		
		
	added queried search
This commit is contained in:
		
							parent
							
								
									bbcf4bd2a7
								
							
						
					
					
						commit
						beab74a4f4
					
				|  | @ -60,6 +60,7 @@ DJANGO_APPS = [ | ||||||
|     "django.contrib.humanize", |     "django.contrib.humanize", | ||||||
|     "django.contrib.admin", |     "django.contrib.admin", | ||||||
|     "django.forms", |     "django.forms", | ||||||
|  |     "django.contrib.postgres", | ||||||
| ] | ] | ||||||
| THIRD_PARTY_APPS = ["rest_framework", "corsheaders", "drf_yasg"] | THIRD_PARTY_APPS = ["rest_framework", "corsheaders", "drf_yasg"] | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,9 +2,19 @@ from rest_framework import serializers | ||||||
| from django.core.validators import MinLengthValidator, MinValueValidator | from django.core.validators import MinLengthValidator, MinValueValidator | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class QueryFilterSerializer(serializers.Serializer): | ||||||
|  |     value = serializers.CharField(max_length=100) | ||||||
|  |     type = serializers.CharField(max_length=100) | ||||||
|  | 
 | ||||||
|  |     def create(self, validated_data): | ||||||
|  |         raise NotImplementedError | ||||||
|  | 
 | ||||||
|  |     def update(self, instance, validated_data): | ||||||
|  |         raise NotImplementedError | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class SearchSerializer(serializers.Serializer): | class SearchSerializer(serializers.Serializer): | ||||||
|     body = serializers.CharField(max_length=200) |     body = serializers.ListSerializer(child=QueryFilterSerializer()) | ||||||
| 
 | 
 | ||||||
|     def create(self, validated_data): |     def create(self, validated_data): | ||||||
|         raise NotImplementedError |         raise NotImplementedError | ||||||
|  |  | ||||||
|  | @ -5,47 +5,60 @@ from rest_framework.response import Response | ||||||
| from rest_framework.views import APIView | from rest_framework.views import APIView | ||||||
| from search.api.serializers import HintRequestSerializer | from search.api.serializers import HintRequestSerializer | ||||||
| 
 | 
 | ||||||
| from search.api.serializers import SearchSerializer, ResponseSerializer, HintResponseSerializer, AutoCompleteRequestSerializer, AutoCompleteResponseSerializer | from search.api.serializers import ( | ||||||
| from search.services.search import process_string |     SearchSerializer, | ||||||
|  |     ResponseSerializer, | ||||||
|  |     HintResponseSerializer, | ||||||
|  |     AutoCompleteRequestSerializer, | ||||||
|  |     AutoCompleteResponseSerializer, | ||||||
|  | ) | ||||||
|  | from search.services.search import process_search | ||||||
| from search.services.autocomplete_schema import autocomplete_schema | from search.services.autocomplete_schema import autocomplete_schema | ||||||
| 
 | 
 | ||||||
| from search.services.hints import get_hints | from search.services.hints import get_hints | ||||||
| 
 | 
 | ||||||
| user_response = openapi.Response("search results", ResponseSerializer) | user_response = openapi.Response("search results", ResponseSerializer) | ||||||
| hint_response = openapi.Response("hints", HintResponseSerializer) | hint_response = openapi.Response("hints", HintResponseSerializer) | ||||||
| autocomplete_response = openapi.Response("autocomplete schema", AutoCompleteResponseSerializer) | autocomplete_response = openapi.Response( | ||||||
|  |     "autocomplete schema", AutoCompleteResponseSerializer | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class SearchApi(APIView): | class SearchApi(APIView): | ||||||
|     @swagger_auto_schema(request_body=SearchSerializer, responses={200: user_response}) |     @swagger_auto_schema(request_body=SearchSerializer, responses={200: user_response}) | ||||||
|     def post(self, request, format=None): |     def post(self, request): | ||||||
|         serializer = SearchSerializer(data=request.data) |         serializer = SearchSerializer(data=request.data) | ||||||
|         serializer.is_valid(raise_exception=True) |         serializer.is_valid(raise_exception=True) | ||||||
|         return Response( |         return Response( | ||||||
|             process_string(serializer.data["body"]), status=status.HTTP_200_OK |             process_search(serializer.data["body"]), status=status.HTTP_200_OK | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class HintApi(APIView): | class HintApi(APIView): | ||||||
|     @swagger_auto_schema(request_body=HintRequestSerializer, responses={200: hint_response}) |     @swagger_auto_schema( | ||||||
|     def post(self, request, format=None): |         request_body=HintRequestSerializer, responses={200: hint_response} | ||||||
|  |     ) | ||||||
|  |     def post(self, request): | ||||||
|         serializer = HintRequestSerializer(data=request.data) |         serializer = HintRequestSerializer(data=request.data) | ||||||
|         serializer.is_valid(raise_exception=True) |         serializer.is_valid(raise_exception=True) | ||||||
|         return Response( |         return Response( | ||||||
|             { |             { | ||||||
|                 'type': get_hints(serializer.data['content']), |                 "type": get_hints(serializer.data["content"]), | ||||||
|                 'value': serializer.data['content'] |                 "value": serializer.data["content"], | ||||||
|             }, |             }, | ||||||
|             status=status.HTTP_200_OK    |             status=status.HTTP_200_OK, | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| class AutoCompleteApi(APIView): | class AutoCompleteApi(APIView): | ||||||
|     @swagger_auto_schema(request_body=AutoCompleteRequestSerializer, responses={200: autocomplete_response}) |     @swagger_auto_schema( | ||||||
|     def post(self, request, format=None): |         request_body=AutoCompleteRequestSerializer, | ||||||
|  |         responses={200: autocomplete_response}, | ||||||
|  |     ) | ||||||
|  |     def post(self, request): | ||||||
|         serializer = AutoCompleteRequestSerializer(data=request.data) |         serializer = AutoCompleteRequestSerializer(data=request.data) | ||||||
|         serializer.is_valid(raise_exception=True) |         serializer.is_valid(raise_exception=True) | ||||||
|         return Response( |         return Response( | ||||||
|             { |             {"nodes": autocomplete_schema(serializer.data["content"])}, | ||||||
|                 'nodes': autocomplete_schema(serializer.data['content']) |             status=status.HTTP_200_OK, | ||||||
|             }, status=status.HTTP_200_OK |  | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  | @ -49,6 +49,8 @@ class Product(models.Model): | ||||||
|         Category, related_name="products", on_delete=models.CASCADE |         Category, related_name="products", on_delete=models.CASCADE | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|  |     # score = models.IntegerField(default=0) | ||||||
|  | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return str(self.name) |         return str(self.name) | ||||||
| 
 | 
 | ||||||
|  | @ -56,13 +58,17 @@ class Product(models.Model): | ||||||
|         return { |         return { | ||||||
|             "name": self.name, |             "name": self.name, | ||||||
|             "characteristic": [ |             "characteristic": [ | ||||||
|                 x.serialize_self() for x in self.characteristics.objects.all() |                 x.characteristic.serialize_self() for x in self.characteristics.all() | ||||||
|             ] |             ] | ||||||
|             + [x.serialize_self() for x in self.unit_characteristics.objects.all()], |             + [ | ||||||
|  |                 x.characteristic.serialize_self() | ||||||
|  |                 for x in self.unit_characteristics.all() | ||||||
|  |             ], | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     class Meta: |     class Meta: | ||||||
|         db_table = "product" |         db_table = "product" | ||||||
|  |         # ordering = ["score"] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ProductCharacteristic(models.Model): | class ProductCharacteristic(models.Model): | ||||||
|  |  | ||||||
|  | @ -1,37 +1,38 @@ | ||||||
| from search.models import Product, Category, Characteristic | from search.models import Product, Category, Characteristic | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def autocomplete_schema(val: str): | def autocomplete_schema(val: str): | ||||||
|     schema = [] |     schema = [] | ||||||
|     schema.extend( |     schema.extend( | ||||||
|         [ |         [ | ||||||
|             { |             { | ||||||
|                 'coordinate': product['name'].index(val), |                 "coordinate": product["name"].index(val), | ||||||
|                 'value': { |                 "value": { | ||||||
|                     'type': 'Name', |                     "type": "Name", | ||||||
|                     'value': product['name'], |                     "value": product["name"], | ||||||
|                 } |                 }, | ||||||
|             } for product in Product.objects.filter(name__contains=val).values('name')] |             } | ||||||
|     ) |             for product in Product.objects.filter(name__contains=val).values("name") | ||||||
|     schema.extend( |  | ||||||
|         [ |  | ||||||
|             { |  | ||||||
|                 'coordinate': cat['name'].index(val), |  | ||||||
|                 'value': { |  | ||||||
|                     'type': 'Category', |  | ||||||
|                     'value': cat['name'] |  | ||||||
|                 } |  | ||||||
|             } for cat in Category.objects.filter(name__contains=val).values('name') |  | ||||||
|         ] |         ] | ||||||
|     ) |     ) | ||||||
|     schema.extend( |     schema.extend( | ||||||
|         [ |         [ | ||||||
|             { |             { | ||||||
|                 'coordinate': char.name.index(val), |                 "coordinate": cat["name"].index(val), | ||||||
|                 'value': { |                 "value": {"type": "Category", "value": cat["name"]}, | ||||||
|                     'type': char.name, |             } | ||||||
|                     'value': char.value |             for cat in Category.objects.filter(name__contains=val).values("name") | ||||||
|                 } |         ] | ||||||
|             } for char in Characteristic.objects.filter(name__contains=val).values('name', 'value') |     ) | ||||||
|  |     schema.extend( | ||||||
|  |         [ | ||||||
|  |             { | ||||||
|  |                 "coordinate": char.name.index(val), | ||||||
|  |                 "value": {"type": char.name, "value": char.value}, | ||||||
|  |             } | ||||||
|  |             for char in Characteristic.objects.filter(name__contains=val).values( | ||||||
|  |                 "name", "value" | ||||||
|  |             ) | ||||||
|         ] |         ] | ||||||
|     ) |     ) | ||||||
|     return schema |     return schema | ||||||
|  |  | ||||||
|  | @ -2,11 +2,11 @@ from search.models import Product, Category, Characteristic | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def get_hints(content: str) -> str: | def get_hints(content: str) -> str: | ||||||
|     category = 'Unknown' |     category = "Unknown" | ||||||
|     if content in list(map(lambda product: product.name, Product.objects.all())): |     if content in list(map(lambda product: product.name, Product.objects.all())): | ||||||
|         category = 'Name' |         category = "Name" | ||||||
|     elif content in list(map(lambda category: category.name, Category.objects.all())): |     elif content in list(map(lambda category: category.name, Category.objects.all())): | ||||||
|         category = 'Category' |         category = "Category" | ||||||
|     elif content in list(map(lambda char: char.value, Characteristic.objects.all())): |     elif content in list(map(lambda char: char.value, Characteristic.objects.all())): | ||||||
|         category = Characteristic.objects.get(value=content).name |         category = Characteristic.objects.get(value=content).name | ||||||
|     return category |     return category | ||||||
|  |  | ||||||
|  | @ -1,6 +1,44 @@ | ||||||
| from search.models import Product | from search.models import Product, Characteristic, ProductCharacteristic | ||||||
| from typing import List | from typing import List | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def process_string(text: str) -> List[dict]: | def process_search(data: List[dict]) -> List[dict]: | ||||||
|     return [x.serialize_self() for x in Product.objects.filter(name__contains=text)[5:]] |     prep_data = [] | ||||||
|  |     prep_dict = {} | ||||||
|  |     prep_dict_char_type = {} | ||||||
|  | 
 | ||||||
|  |     for x in data: | ||||||
|  |         dat = dict(x) | ||||||
|  |         if x["type"] in ["Name", "Category", "Unknown"]: | ||||||
|  |             prep_data.append(dat) | ||||||
|  |         else: | ||||||
|  |             if x["type"] in list(prep_dict.keys()): | ||||||
|  |                 prep_dict[x["type"]] = prep_dict[ | ||||||
|  |                     x["type"] | ||||||
|  |                 ] | ProductCharacteristic.objects.filter( | ||||||
|  |                     characteristic__in=prep_dict_char_type[x["type"]], | ||||||
|  |                     characteristic__value__unaccent__trigram_similar=x["value"], | ||||||
|  |                 ) | ||||||
|  |             else: | ||||||
|  |                 prep_dict_char_type[x["type"]] = Characteristic.objects.filter( | ||||||
|  |                     name__contains=x["type"] | ||||||
|  |                 ) | ||||||
|  |                 prep_dict[x["type"]] = ProductCharacteristic.objects.filter( | ||||||
|  |                     characteristic__in=prep_dict_char_type[x["type"]], | ||||||
|  |                     characteristic__value__unaccent__trigram_similar=x["value"], | ||||||
|  |                 ) | ||||||
|  |     for el, val in prep_dict.items(): | ||||||
|  |         prep_data.append({"type": el, "value": val}) | ||||||
|  |     qs = Product.objects.filter() | ||||||
|  |     for x in prep_data: | ||||||
|  |         typ = x["type"] | ||||||
|  |         val = x["value"] | ||||||
|  |         if typ == "Name": | ||||||
|  |             qs = qs.filter(name__unaccent__trigram_similar=val) | ||||||
|  |         elif typ == "Category": | ||||||
|  |             qs = qs.filter(category__name__unaccent__trigram_similar=val) | ||||||
|  |         elif typ == "Unknown": | ||||||
|  |             continue | ||||||
|  |         else: | ||||||
|  |             qs = qs.filter(characteristics__in=val) | ||||||
|  |     return [x.serialize_self() for x in qs[:5]] | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user