Enable filtering by attribute values

This commit is contained in:
Jeremy Stretch 2025-03-28 12:25:34 -04:00
parent 4fd3a91d2f
commit 94b3aae0a2
3 changed files with 31 additions and 3 deletions

View File

@ -11,7 +11,7 @@ from ipam.filtersets import PrimaryIPFilterSet
from ipam.models import ASN, IPAddress, VLANTranslationPolicy, VRF from ipam.models import ASN, IPAddress, VLANTranslationPolicy, VRF
from netbox.choices import ColorChoices from netbox.choices import ColorChoices
from netbox.filtersets import ( from netbox.filtersets import (
BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet, NetBoxModelFilterSet, AttributeFiltersMixin, BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet, NetBoxModelFilterSet,
OrganizationalModelFilterSet, OrganizationalModelFilterSet,
) )
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
@ -691,7 +691,7 @@ class ModuleTypeProfileFilterSet(NetBoxModelFilterSet):
) )
class ModuleTypeFilterSet(NetBoxModelFilterSet): class ModuleTypeFilterSet(AttributeFiltersMixin, NetBoxModelFilterSet):
profile_id = django_filters.ModelMultipleChoiceFilter( profile_id = django_filters.ModelMultipleChoiceFilter(
queryset=ModuleTypeProfile.objects.all(), queryset=ModuleTypeProfile.objects.all(),
label=_('Profile (ID)'), label=_('Profile (ID)'),

View File

@ -128,7 +128,7 @@ class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
""" """
Returns a human-friendly representation of the attributes defined for a ModuleType according to its profile. Returns a human-friendly representation of the attributes defined for a ModuleType according to its profile.
""" """
if self.profile is None or not self.profile.schema: if not self.attribute_data or self.profile is None or not self.profile.schema:
return {} return {}
attrs = {} attrs = {}
for name, options in self.profile.schema.get('properties', {}).items(): for name, options in self.profile.schema.get('properties', {}).items():

View File

@ -1,3 +1,5 @@
import json
import django_filters import django_filters
from copy import deepcopy from copy import deepcopy
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -20,6 +22,7 @@ from utilities.forms.fields import MACAddressField
from utilities import filters from utilities import filters
__all__ = ( __all__ = (
'AttributeFiltersMixin',
'BaseFilterSet', 'BaseFilterSet',
'ChangeLoggedModelFilterSet', 'ChangeLoggedModelFilterSet',
'NetBoxModelFilterSet', 'NetBoxModelFilterSet',
@ -345,3 +348,28 @@ class NestedGroupModelFilterSet(NetBoxModelFilterSet):
) )
return queryset return queryset
class AttributeFiltersMixin:
attributes_field_name = 'attribute_data'
attribute_filter_prefix = 'attr_'
def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
self.attr_filters = {}
# Extract JSONField-based filters from the incoming data
if data is not None:
for key, value in data.items():
if key.startswith(self.attribute_filter_prefix):
# Attempt to case the value to a native JSON type
try:
value = json.loads(value)
except (ValueError, json.JSONDecodeError):
pass
field = f'{self.attributes_field_name}__{key.split(self.attribute_filter_prefix, 1)[1]}'
self.attr_filters[field] = value
super().__init__(data=data, queryset=queryset, request=request, prefix=prefix)
def filter_queryset(self, queryset):
return super().filter_queryset(queryset).filter(**self.attr_filters)