mirror of
https://github.com/magnum-opus-tender-hack/backend.git
synced 2025-02-19 19:00:32 +03:00
added score system, range unit characteristics, minor improvements
This commit is contained in:
parent
c68dfce10a
commit
faaccff7dc
|
@ -1,9 +1,15 @@
|
|||
from django.urls import path
|
||||
|
||||
from search.api.views import SearchApi, HintApi, AutoCompleteApi
|
||||
from search.api.views import (
|
||||
SearchApi,
|
||||
HintApi,
|
||||
AutoCompleteApi,
|
||||
IncreaseProductScoreApi,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path("search", SearchApi.as_view(), name="search_api"),
|
||||
path("hint", HintApi.as_view(), name="hint api"),
|
||||
path('autocomplete_schema', AutoCompleteApi.as_view(), name='autocomplete api')
|
||||
path("hint", HintApi.as_view(), name="hint_api"),
|
||||
path("autocomplete_schema", AutoCompleteApi.as_view(), name="autocomplete_api"),
|
||||
path("score/<int:pk>", IncreaseProductScoreApi.as_view(), name="score_api"),
|
||||
]
|
||||
|
|
|
@ -58,7 +58,7 @@ class HintResponseSerializer(serializers.Serializer):
|
|||
|
||||
class AutoCompleteRequestSerializer(serializers.Serializer):
|
||||
content = serializers.CharField(validators=[MinLengthValidator(3)])
|
||||
exclude = serializers.ListSerializer(child=QueryFilterSerializer())
|
||||
exclude = serializers.ListSerializer(child=QueryFilterSerializer(), default=[])
|
||||
|
||||
def create(self, validated_data):
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework import status
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from search.api.serializers import HintRequestSerializer
|
||||
|
@ -12,6 +13,7 @@ from search.api.serializers import (
|
|||
AutoCompleteRequestSerializer,
|
||||
AutoCompleteResponseSerializer,
|
||||
)
|
||||
from search.models import Product
|
||||
from search.services.search import process_search
|
||||
from search.services.autocomplete_schema import autocomplete_schema
|
||||
|
||||
|
@ -64,6 +66,28 @@ class AutoCompleteApi(APIView):
|
|||
serializer = AutoCompleteRequestSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
return Response(
|
||||
{"nodes": autocomplete_schema(serializer.data["content"], serializer.data["exclude"])},
|
||||
{
|
||||
"nodes": autocomplete_schema(
|
||||
serializer.data["content"], serializer.data["exclude"]
|
||||
)
|
||||
},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
class IncreaseProductScoreApi(APIView):
|
||||
@swagger_auto_schema(
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
"id",
|
||||
openapi.IN_PATH,
|
||||
description="Product id",
|
||||
type=openapi.TYPE_INTEGER,
|
||||
)
|
||||
]
|
||||
)
|
||||
def post(self, request, pk):
|
||||
product = get_object_or_404(Product, id=pk)
|
||||
product.score += 1
|
||||
product.save(update_fields=["score"])
|
||||
return Response({"score": product.score}, status=status.HTTP_200_OK)
|
||||
|
|
|
@ -18,14 +18,22 @@ class Characteristic(models.Model):
|
|||
class UnitCharacteristic(models.Model):
|
||||
name = models.TextField("Имя", blank=False)
|
||||
value = models.TextField("Значение", blank=False)
|
||||
numeric_value = models.IntegerField(default=0)
|
||||
numeric_value_min = models.IntegerField(default=0)
|
||||
numeric_value_max = models.IntegerField(default=0)
|
||||
unit = models.TextField("Размерность", blank=False)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
def serialize_self(self):
|
||||
return {"name": self.name, "value": self.numeric_value, "unit": self.unit}
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"value": self.numeric_value_min
|
||||
if self.numeric_value_min == self.numeric_value_max
|
||||
else f"{self.numeric_value_min}:{self.numeric_value_max}",
|
||||
"unit": self.unit,
|
||||
}
|
||||
|
||||
class Meta:
|
||||
db_table = "unit_characteristic"
|
||||
|
@ -50,14 +58,16 @@ class Product(models.Model):
|
|||
Category, related_name="products", on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
# score = models.IntegerField(default=0)
|
||||
score = models.IntegerField(default=0)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name)
|
||||
|
||||
def serialize_self(self) -> dict:
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"score": self.score,
|
||||
"characteristic": [
|
||||
x.characteristic.serialize_self() for x in self.characteristics.all()
|
||||
]
|
||||
|
@ -69,7 +79,7 @@ class Product(models.Model):
|
|||
|
||||
class Meta:
|
||||
db_table = "product"
|
||||
# ordering = ["score"]
|
||||
ordering = ["-score"]
|
||||
|
||||
|
||||
class ProductCharacteristic(models.Model):
|
||||
|
|
|
@ -18,9 +18,9 @@ def autocomplete_schema(val: str, exclude: List[Dict]):
|
|||
"value": product["name"],
|
||||
},
|
||||
}
|
||||
for product in Product.objects.filter(
|
||||
name__unaccent__icontains=val
|
||||
).values("name")
|
||||
for product in Product.objects.filter(name__unaccent__icontains=val)[
|
||||
:20
|
||||
].values("name")
|
||||
]
|
||||
)
|
||||
if not category_exclude:
|
||||
|
@ -30,9 +30,9 @@ def autocomplete_schema(val: str, exclude: List[Dict]):
|
|||
"coordinate": cat["name"].lower().index(val.lower()),
|
||||
"value": {"type": "Category", "value": cat["name"]},
|
||||
}
|
||||
for cat in Category.objects.filter(
|
||||
name__unaccent__icontains=val
|
||||
).values("name")
|
||||
for cat in Category.objects.filter(name__unaccent__icontains=val)[
|
||||
:20
|
||||
].values("name")
|
||||
]
|
||||
)
|
||||
schema.extend(
|
||||
|
@ -41,9 +41,9 @@ def autocomplete_schema(val: str, exclude: List[Dict]):
|
|||
"coordinate": char["value"].lower().index(val.lower()),
|
||||
"value": {"type": char["name"], "value": char["value"]},
|
||||
}
|
||||
for char in Characteristic.objects.filter(
|
||||
value__unaccent__icontains=val
|
||||
).values("name", "value")
|
||||
for char in Characteristic.objects.filter(value__unaccent__icontains=val)[
|
||||
:20
|
||||
].values("name", "value")
|
||||
]
|
||||
)
|
||||
return schema
|
||||
|
|
|
@ -64,12 +64,23 @@ def load_excel():
|
|||
|
||||
def process_unit_character():
|
||||
for el in UnitCharacteristic.objects.all():
|
||||
nums = re.findall("[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", el.value)
|
||||
if len(nums) != 1:
|
||||
el.delete()
|
||||
else:
|
||||
nums = re.findall(
|
||||
"[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", el.value
|
||||
)
|
||||
if len(nums) == 1:
|
||||
try:
|
||||
el.numeric_value = int(float(nums[0].replace(",", ".")))
|
||||
el.numeric_value_min = int(float(nums[0].replace(",", ".")))
|
||||
el.numeric_value_max = int(float(nums[0].replace(",", ".")))
|
||||
el.save()
|
||||
except ValueError:
|
||||
el.delete()
|
||||
elif len(nums):
|
||||
try:
|
||||
nums = [int(float(x.replace(",", "."))) for x in nums]
|
||||
min_num = min(nums)
|
||||
max_num = max(nums)
|
||||
el.numeric_value_min = min_num
|
||||
el.numeric_value_max = max_num
|
||||
el.save()
|
||||
except ValueError:
|
||||
el.delete()
|
||||
|
|
|
@ -16,15 +16,26 @@ from search.services.translate import translate_en_ru, translate_ru_en
|
|||
|
||||
def process_unit_operation(unit: ProductUnitCharacteristic.objects, operation: str):
|
||||
if operation.startswith("<=") or operation.startswith("=<"):
|
||||
return unit.filter(characteristic__numeric_value__lte=int(float(operation[2:])))
|
||||
return unit.filter(
|
||||
characteristic__numeric_value_max__lte=int(float(operation[2:]))
|
||||
)
|
||||
elif operation.startswith("=>") or operation.startswith(">="):
|
||||
return unit.filter(characteristic__numeric_value__gte=int(float(operation[2:])))
|
||||
return unit.filter(
|
||||
characteristic__numeric_value_min__gte=int(float(operation[2:]))
|
||||
)
|
||||
elif operation.startswith(">"):
|
||||
return unit.filter(characteristic__numeric_value__gt=int(float(operation[1:])))
|
||||
return unit.filter(
|
||||
characteristic__numeric_value_min__gt=int(float(operation[1:]))
|
||||
)
|
||||
elif operation.startswith("<"):
|
||||
return unit.filter(characteristic__numeric_value__lt=int(float(operation[1:])))
|
||||
return unit.filter(
|
||||
characteristic__numeric_value_max__lt=int(float(operation[1:]))
|
||||
)
|
||||
elif operation.startswith("="):
|
||||
return unit.filter(characteristic__numeric_value=int(float(operation[1:])))
|
||||
return unit.filter(
|
||||
characteristic__numeric_value_min__gte=int(float(operation[1:])),
|
||||
characteristic__numeric_value_max__lte=int(float(operation[1:])),
|
||||
)
|
||||
return unit
|
||||
|
||||
|
||||
|
@ -33,7 +44,9 @@ def apply_qs_search(qs: Product.objects, text: str):
|
|||
text = text.replace(st, " ")
|
||||
text = text.split()
|
||||
for word in text:
|
||||
qs = qs.filter(name__unaccent__trigram_similar=word) | qs.filter(name__unaccent__icontains=word)
|
||||
qs = qs.filter(name__unaccent__trigram_similar=word) | qs.filter(
|
||||
name__unaccent__icontains=word
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user