diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index e3faa6332..f719290ed 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filters.py @@ -3,11 +3,12 @@ import django_filters from django.db.models import Q from dcim.models import Site +from extras.filters import CustomFieldFilterSet from tenancy.models import Tenant from .models import Provider, Circuit, CircuitType -class ProviderFilter(django_filters.FilterSet): +class ProviderFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', @@ -36,7 +37,7 @@ class ProviderFilter(django_filters.FilterSet): ) -class CircuitFilter(django_filters.FilterSet): +class CircuitFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 3033ce564..eac47445e 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -2,14 +2,15 @@ import django_filters from django.db.models import Q +from extras.filters import CustomFieldFilterSet +from tenancy.models import Tenant from .models import ( ConsolePort, ConsoleServerPort, Device, DeviceRole, DeviceType, Interface, InterfaceConnection, Manufacturer, Platform, PowerOutlet, PowerPort, Rack, RackGroup, RackRole, Site, ) -from tenancy.models import Tenant -class SiteFilter(django_filters.FilterSet): +class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', @@ -58,7 +59,7 @@ class RackGroupFilter(django_filters.FilterSet): fields = ['site_id', 'site'] -class RackFilter(django_filters.FilterSet): +class RackFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', @@ -139,7 +140,7 @@ class DeviceTypeFilter(django_filters.FilterSet): 'is_network_device'] -class DeviceFilter(django_filters.FilterSet): +class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py new file mode 100644 index 000000000..d482aa126 --- /dev/null +++ b/netbox/extras/filters.py @@ -0,0 +1,31 @@ +import django_filters + +from django.contrib.contenttypes.models import ContentType + +from .models import CustomField + + +class CustomFieldFilter(django_filters.Filter): + """ + Filter objects by the presence of a CustomFieldValue. The filter's name is used as the CustomField name. + """ + + def filter(self, queryset, value): + return queryset.filter( + custom_field_values__field__name=self.name, + custom_field_values__serialized_value=value, + ) + + +class CustomFieldFilterSet(django_filters.FilterSet): + """ + Dynamically add a Filter for each CustomField applicable to the parent model. + """ + + def __init__(self, *args, **kwargs): + super(CustomFieldFilterSet, self).__init__(*args, **kwargs) + + obj_type = ContentType.objects.get_for_model(self._meta.model) + custom_fields = CustomField.objects.filter(obj_type=obj_type) + for cf in custom_fields: + self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(name=cf.name) diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index 3a73caf84..be2d127b5 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -5,12 +5,13 @@ from netaddr.core import AddrFormatError from django.db.models import Q from dcim.models import Site, Device, Interface +from extras.filters import CustomFieldFilterSet from tenancy.models import Tenant from .models import RIR, Aggregate, VRF, Prefix, IPAddress, VLAN, VLANGroup, Role -class VRFFilter(django_filters.FilterSet): +class VRFFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', @@ -44,7 +45,7 @@ class VRFFilter(django_filters.FilterSet): fields = ['name', 'rd'] -class AggregateFilter(django_filters.FilterSet): +class AggregateFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', @@ -75,7 +76,7 @@ class AggregateFilter(django_filters.FilterSet): return queryset.filter(qs_filter) -class PrefixFilter(django_filters.FilterSet): +class PrefixFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', @@ -186,7 +187,7 @@ class PrefixFilter(django_filters.FilterSet): ) -class IPAddressFilter(django_filters.FilterSet): +class IPAddressFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', @@ -300,7 +301,7 @@ class VLANGroupFilter(django_filters.FilterSet): fields = ['site_id', 'site'] -class VLANFilter(django_filters.FilterSet): +class VLANFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search', diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filters.py index 3493c94ea..01d2d578d 100644 --- a/netbox/tenancy/filters.py +++ b/netbox/tenancy/filters.py @@ -2,10 +2,11 @@ import django_filters from django.db.models import Q +from extras.filters import CustomFieldFilterSet from .models import Tenant, TenantGroup -class TenantFilter(django_filters.FilterSet): +class TenantFilter(CustomFieldFilterSet, django_filters.FilterSet): q = django_filters.MethodFilter( action='search', label='Search',