66from extras .filters import TagFilter
77from netbox .filtersets import NetBoxModelFilterSet
88
9+
910from cesnet_service_path_plugin .models import Segment
1011from cesnet_service_path_plugin .models .custom_choices import StatusChoices
1112from cesnet_service_path_plugin .models .segment_types import SegmentTypeChoices
@@ -86,7 +87,7 @@ class SegmentFilterSet(NetBoxModelFilterSet):
8687 )
8788
8889 # Path data filter
89- has_path_data = django_filters .MultipleChoiceFilter (
90+ has_path_data = django_filters .ChoiceFilter (
9091 choices = [
9192 (True , "Yes" ),
9293 (False , "No" ),
@@ -95,6 +96,16 @@ class SegmentFilterSet(NetBoxModelFilterSet):
9596 label = "Has Path Data" ,
9697 )
9798
99+ # Type specific data filter
100+ has_type_specific_data = django_filters .ChoiceFilter (
101+ choices = [
102+ (True , "Yes" ),
103+ (False , "No" ),
104+ ],
105+ method = "_has_type_specific_data" ,
106+ label = "Has Type Specific Data" ,
107+ )
108+
98109 # =============================================================================
99110 # TYPE-SPECIFIC FILTERS
100111 # =============================================================================
@@ -218,6 +229,7 @@ class Meta:
218229 "site_b" ,
219230 "location_b" ,
220231 "has_path_data" ,
232+ "has_type_specific_data" ,
221233 ]
222234
223235 def _at_any_site (self , queryset , name , value ):
@@ -239,38 +251,33 @@ def _at_any_location(self, queryset, name, value):
239251 def _has_path_data (self , queryset , name , value ):
240252 """
241253 Filter segments based on whether they have path data or not
242-
243- Args:
244- value: List of selected values from choices
245- [True] - show only segments with path data
246- [False] - show only segments without path data
247- [True, False] - show all segments (both with and without)
248- [] - show all segments (nothing selected)
249254 """
250- if not value :
255+ if value in ( None , "" , []) :
251256 # Nothing selected, show all segments
252257 return queryset
253258
254- # Convert string values to boolean (django-filter sometimes passes strings)
255- bool_values = []
256- for v in value :
257- if v is True or v == "True" or v :
258- bool_values .append (True )
259- elif v is False or v == "False" or not v :
260- bool_values .append (False )
259+ has_data = value in [True , "True" , "true" , "1" ]
261260
262- if True in bool_values and False in bool_values :
263- # Both selected, show all segments
264- return queryset
265- elif True in bool_values :
261+ if has_data :
266262 # Only "Yes" selected, show segments with path data
267263 return queryset .filter (path_geometry__isnull = False )
268- elif False in bool_values :
264+ else :
269265 # Only "No" selected, show segments without path data
270266 return queryset .filter (path_geometry__isnull = True )
267+
268+ def _has_type_specific_data (self , queryset , name , value ):
269+ """Filter segments by whether they have type-specific data"""
270+ if value == "" or value is None :
271+ return queryset # No filtering
272+
273+ has_data = value in [True , "True" , "true" , "1" ]
274+
275+ if has_data :
276+ # Has data: exclude null and empty dict
277+ return queryset .exclude (Q (type_specific_data__isnull = True ) | Q (type_specific_data = {}))
271278 else :
272- # Fallback: show all segments
273- return queryset
279+ # No data: include null or empty dict
280+ return queryset . filter ( Q ( type_specific_data__isnull = True ) | Q ( type_specific_data = {}))
274281
275282 def _parse_smart_numeric_value (self , value , field_type = "float" ):
276283 """
0 commit comments