1717
1818from common .fields import translation_fields
1919from common .filters import DefaultingDateFilter , MultiFieldFilter , UpperCaseFilter
20+ from common .models import ClassifiedProduct
2021from common .utils import make_condition_funcs
2122from common .viewsets import AggregatingViewSet , BaseModelViewSet
22- from metadata .models import WealthGroupCategory
23+ from metadata .models import LivelihoodStrategyType , WealthGroupCategory
2324
2425from .models import (
2526 BaselineLivelihoodActivity ,
@@ -212,6 +213,7 @@ class Meta:
212213 wealth_characteristic = CharFilter (
213214 method = "filter_by_wealth_characteristic" , label = "Filter by Wealth Characteristic"
214215 )
216+ strategy_type = CharFilter (method = "filter_by_strategy_type" , label = "Filter by Strategy Type" )
215217 as_of_date = DefaultingDateFilter (
216218 label = "As of Date" ,
217219 help_text = "Filter baselines valid as of this date (YYYY-MM-DD format or special values like 'today')." ,
@@ -257,6 +259,13 @@ def filter_by_wealth_characteristic(self, queryset, name, value):
257259
258260 return queryset .filter (id__in = Subquery (matching_baselines ))
259261
262+ def filter_by_strategy_type (self , queryset , name , value ):
263+ """
264+ Filter the baseline by matching livelihood strategy type
265+ """
266+ matching_baselines = LivelihoodStrategy .objects .filter (strategy_type = value ).values ("livelihood_zone_baseline" )
267+ return queryset .filter (id__in = Subquery (matching_baselines ))
268+
260269
261270class LivelihoodZoneBaselineViewSet (BaseModelViewSet ):
262271 """
@@ -2088,6 +2097,16 @@ class LivelihoodZoneBaselineFacetedSearchView(APIView):
20882097 renderer_classes = [JSONRenderer ]
20892098 permission_classes = [AllowAny ]
20902099
2100+ def _search_products (self , search_term ):
2101+ # Search products using icontains for broader matching than the default iexact search.
2102+ q_object = Q ()
2103+ for field in [* translation_fields ("description" ), * translation_fields ("common_name" )]:
2104+ q_object |= Q (** {f"{ field } __icontains" : search_term })
2105+ q_object |= Q (cpc__iexact = search_term )
2106+ q_object |= Q (aliases__contains = [search_term .lower ()])
2107+ q_object |= Q (scientific_name__icontains = search_term )
2108+ return ClassifiedProduct .objects .filter (q_object ).distinct ()
2109+
20912110 def get (self , request , format = None ):
20922111 """
20932112 Return a faceted set of matching filters
@@ -2100,13 +2119,14 @@ def get(self, request, format=None):
21002119 for model_entry in MODELS_TO_SEARCH :
21012120 app_name = model_entry ["app_name" ]
21022121 model_name = model_entry ["model_name" ]
2103- filter , filter_label , filter_category = (
2104- model_entry ["filter" ]["key" ],
2105- model_entry ["filter" ]["label" ],
2106- model_entry ["filter" ]["category" ],
2107- )
2122+ filter_key = model_entry ["filter" ]["key" ]
2123+ filter_label = model_entry ["filter" ]["label" ]
2124+ filter_category = model_entry ["filter" ]["category" ]
21082125 ModelClass = apps .get_model (app_name , model_name )
2109- search_per_model = ModelClass .objects .search (search_term )
2126+ if model_name == "ClassifiedProduct" :
2127+ search_per_model = self ._search_products (search_term )
2128+ else :
2129+ search_per_model = ModelClass .objects .search (search_term )
21102130 results [filter_category ] = []
21112131 # for activating language
21122132 with override (language ):
@@ -2145,12 +2165,45 @@ def get(self, request, format=None):
21452165 if unique_zones > 0 :
21462166 results [filter_category ].append (
21472167 {
2148- "filter" : filter ,
2168+ "filter" : filter_key ,
21492169 "filter_label" : filter_label ,
21502170 "value_label" : value_label ,
21512171 "value" : value ,
21522172 "count" : unique_zones ,
21532173 }
21542174 )
21552175
2176+ # Search livelihood strategy types (not a model query)
2177+ results ["livelihood_strategy_types" ] = []
2178+ search_lower = search_term .lower ()
2179+ # Get English labels outside language override for matching
2180+ english_labels = {}
2181+ with override ("en" ):
2182+ for strategy_type in LivelihoodStrategyType :
2183+ english_labels [strategy_type .value ] = str (strategy_type .label ).lower ()
2184+ with override (language ):
2185+ for strategy_type in LivelihoodStrategyType :
2186+ translated_label = str (strategy_type .label )
2187+ if (
2188+ search_lower in strategy_type .value .lower ()
2189+ or search_lower in english_labels [strategy_type .value ]
2190+ or search_lower in translated_label .lower ()
2191+ ):
2192+ unique_zones = (
2193+ LivelihoodStrategy .objects .filter (strategy_type = strategy_type .value )
2194+ .values ("livelihood_zone_baseline" )
2195+ .distinct ()
2196+ .count ()
2197+ )
2198+ if unique_zones > 0 :
2199+ results ["livelihood_strategy_types" ].append (
2200+ {
2201+ "filter" : "strategy_type" ,
2202+ "filter_label" : "Livelihood Strategy Type" ,
2203+ "value_label" : translated_label ,
2204+ "value" : strategy_type .value ,
2205+ "count" : unique_zones ,
2206+ }
2207+ )
2208+
21562209 return Response (results )
0 commit comments