diff --git a/app/views.py b/app/views.py index 1500b5e..79fc988 100644 --- a/app/views.py +++ b/app/views.py @@ -46,47 +46,34 @@ class HsCodeSearchView(generics.ListAPIView): permission_classes = [] def get_queryset(self): - try: - q = self.request.query_params.get("q") - - if not q: - logger.warning( - "Missing search query | path={path}", - path=self.request.path, - ) - raise ValidationError({"q": ["This query parameter is required."]}) - - threshold = getattr( - settings, - "HS_CODE_SEARCH_THRESHOLD", - 0.1, - ) - - logger.info( - "HS search executed | query={q} | threshold={threshold}", - q=q, - threshold=threshold, - ) - - queryset = ( - HsCode.objects.annotate( - similarity=( - TrigramSimilarity("description", q) * 2 - + TrigramSimilarity("hs_code", q) - ) - ) - .filter(similarity__gte=threshold) - .order_by("-similarity") - ) - return queryset - - except Exception as e: - logger.exception( - "HS search failed | query={q} | error={error}", - q=self.request.query_params.get("q"), - error=str(e), - ) - raise + q = self.request.query_params.get("q", "").strip() + + if not q: + raise ValidationError({"q": ["This query parameter is required."]}) + + exact_qs = HsCode.objects.filter( + Q(description__icontains=q) | Q(hs_code__icontains=q) + ) + + if exact_qs.exists(): + logger.info("HS search (exact) | query={q}", q=q) + return exact_qs.order_by("hs_code") + + threshold = getattr(settings, "HS_CODE_SEARCH_THRESHOLD", 0.3) + + queryset = ( + HsCode.objects.annotate( + similarity=TrigramSimilarity("description", q) + ) + .filter(similarity__gte=threshold) + .order_by("-similarity") + ) + + logger.info( + "HS search (fuzzy) | query={q} | threshold={threshold}", + q=q, threshold=threshold, + ) + return queryset class HealthCheckView(APIView):