From 0de50e0afefcb96337882116007a70d7d0e3eed4 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Apr 2021 15:13:44 -0400 Subject: [PATCH 1/5] Split Filter and FilterSet classes --- netbox/circuits/filters.py | 5 +- netbox/dcim/filters.py | 4 +- netbox/extras/filters.py | 3 +- netbox/ipam/filters.py | 5 +- netbox/secrets/filters.py | 3 +- netbox/tenancy/filters.py | 3 +- netbox/users/filters.py | 2 +- netbox/utilities/filters.py | 190 +------------------------ netbox/utilities/filtersets.py | 190 +++++++++++++++++++++++++ netbox/utilities/tests/test_filters.py | 5 +- netbox/virtualization/filters.py | 6 +- 11 files changed, 211 insertions(+), 205 deletions(-) create mode 100644 netbox/utilities/filtersets.py diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index 034a99ac9..7e0b1cade 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filters.py @@ -5,9 +5,8 @@ from dcim.filters import CableTerminationFilterSet from dcim.models import Region, Site, SiteGroup from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from tenancy.filters import TenancyFilterSet -from utilities.filters import ( - BaseFilterSet, NameSlugSearchFilterSet, TagFilter, TreeNodeMultipleChoiceFilter -) +from utilities.filters import TagFilter, TreeNodeMultipleChoiceFilter +from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet from .choices import * from .models import * diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 29c4281ba..777ca5884 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -6,9 +6,9 @@ from tenancy.filters import TenancyFilterSet from tenancy.models import Tenant from utilities.choices import ColorChoices from utilities.filters import ( - BaseFilterSet, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, - NameSlugSearchFilterSet, TagFilter, TreeNodeMultipleChoiceFilter, + MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, TagFilter, TreeNodeMultipleChoiceFilter, ) +from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet from virtualization.models import Cluster from .choices import * from .constants import * diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index aacdbda6b..9105da81f 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -6,7 +6,8 @@ from django.forms import DateField, IntegerField, NullBooleanField from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup from tenancy.models import Tenant, TenantGroup -from utilities.filters import BaseFilterSet, ContentTypeFilter +from utilities.filtersets import BaseFilterSet +from utilities.filters import ContentTypeFilter from virtualization.models import Cluster, ClusterGroup from .choices import * from .models import * diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index 8f4030411..af047424f 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -9,9 +9,10 @@ from dcim.models import Device, Interface, Region, Site, SiteGroup from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from tenancy.filters import TenancyFilterSet from utilities.filters import ( - BaseFilterSet, ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NameSlugSearchFilterSet, - NumericArrayFilter, TagFilter, TreeNodeMultipleChoiceFilter, + ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TagFilter, + TreeNodeMultipleChoiceFilter, ) +from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet from virtualization.models import VirtualMachine, VMInterface from .choices import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF diff --git a/netbox/secrets/filters.py b/netbox/secrets/filters.py index fb36c827a..ec41ac364 100644 --- a/netbox/secrets/filters.py +++ b/netbox/secrets/filters.py @@ -3,7 +3,8 @@ from django.db.models import Q from dcim.models import Device from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet -from utilities.filters import BaseFilterSet, NameSlugSearchFilterSet, TagFilter +from utilities.filters import TagFilter +from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet from virtualization.models import VirtualMachine from .models import Secret, SecretRole diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filters.py index 0581866a4..8d43a3794 100644 --- a/netbox/tenancy/filters.py +++ b/netbox/tenancy/filters.py @@ -2,7 +2,8 @@ import django_filters from django.db.models import Q from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet -from utilities.filters import BaseFilterSet, NameSlugSearchFilterSet, TagFilter, TreeNodeMultipleChoiceFilter +from utilities.filters import TagFilter, TreeNodeMultipleChoiceFilter +from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet from .models import Tenant, TenantGroup diff --git a/netbox/users/filters.py b/netbox/users/filters.py index 359cf9cc7..42f97bedc 100644 --- a/netbox/users/filters.py +++ b/netbox/users/filters.py @@ -3,7 +3,7 @@ from django.contrib.auth.models import Group, User from django.db.models import Q from users.models import ObjectPermission -from utilities.filters import BaseFilterSet +from utilities.filtersets import BaseFilterSet __all__ = ( 'GroupFilterSet', diff --git a/netbox/utilities/filters.py b/netbox/utilities/filters.py index 6305c0bba..97608ed22 100644 --- a/netbox/utilities/filters.py +++ b/netbox/utilities/filters.py @@ -1,17 +1,10 @@ import django_filters -from django_filters.constants import EMPTY_VALUES -from copy import deepcopy -from dcim.forms import MACAddressField from django import forms from django.conf import settings -from django.db import models -from django_filters.utils import get_model_field, resolve_field +from django_filters.constants import EMPTY_VALUES +from dcim.forms import MACAddressField from extras.models import Tag -from utilities.constants import ( - FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP, - FILTER_NUMERIC_BASED_LOOKUP_MAP -) def multivalue_field_factory(field_class): @@ -134,182 +127,3 @@ class ContentTypeFilter(django_filters.CharFilter): f'{self.field_name}__model': model } ) - - -# -# FilterSets -# - -class BaseFilterSet(django_filters.FilterSet): - """ - A base filterset which provides common functionaly to all NetBox filtersets - """ - FILTER_DEFAULTS = deepcopy(django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS) - FILTER_DEFAULTS.update({ - models.AutoField: { - 'filter_class': MultiValueNumberFilter - }, - models.CharField: { - 'filter_class': MultiValueCharFilter - }, - models.DateField: { - 'filter_class': MultiValueDateFilter - }, - models.DateTimeField: { - 'filter_class': MultiValueDateTimeFilter - }, - models.DecimalField: { - 'filter_class': MultiValueNumberFilter - }, - models.EmailField: { - 'filter_class': MultiValueCharFilter - }, - models.FloatField: { - 'filter_class': MultiValueNumberFilter - }, - models.IntegerField: { - 'filter_class': MultiValueNumberFilter - }, - models.PositiveIntegerField: { - 'filter_class': MultiValueNumberFilter - }, - models.PositiveSmallIntegerField: { - 'filter_class': MultiValueNumberFilter - }, - models.SlugField: { - 'filter_class': MultiValueCharFilter - }, - models.SmallIntegerField: { - 'filter_class': MultiValueNumberFilter - }, - models.TimeField: { - 'filter_class': MultiValueTimeFilter - }, - models.URLField: { - 'filter_class': MultiValueCharFilter - }, - MACAddressField: { - 'filter_class': MultiValueMACAddressFilter - }, - }) - - @staticmethod - def _get_filter_lookup_dict(existing_filter): - # Choose the lookup expression map based on the filter type - if isinstance(existing_filter, ( - MultiValueDateFilter, - MultiValueDateTimeFilter, - MultiValueNumberFilter, - MultiValueTimeFilter - )): - lookup_map = FILTER_NUMERIC_BASED_LOOKUP_MAP - - elif isinstance(existing_filter, ( - TreeNodeMultipleChoiceFilter, - )): - # TreeNodeMultipleChoiceFilter only support negation but must maintain the `in` lookup expression - lookup_map = FILTER_TREENODE_NEGATION_LOOKUP_MAP - - elif isinstance(existing_filter, ( - django_filters.ModelChoiceFilter, - django_filters.ModelMultipleChoiceFilter, - TagFilter - )) or existing_filter.extra.get('choices'): - # These filter types support only negation - lookup_map = FILTER_NEGATION_LOOKUP_MAP - - elif isinstance(existing_filter, ( - django_filters.filters.CharFilter, - django_filters.MultipleChoiceFilter, - MultiValueCharFilter, - MultiValueMACAddressFilter - )): - lookup_map = FILTER_CHAR_BASED_LOOKUP_MAP - - else: - lookup_map = None - - return lookup_map - - @classmethod - def get_filters(cls): - """ - Override filter generation to support dynamic lookup expressions for certain filter types. - - For specific filter types, new filters are created based on defined lookup expressions in - the form `__` - """ - filters = super().get_filters() - - new_filters = {} - for existing_filter_name, existing_filter in filters.items(): - # Loop over existing filters to extract metadata by which to create new filters - - # If the filter makes use of a custom filter method or lookup expression skip it - # as we cannot sanely handle these cases in a generic mannor - if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'in']: - continue - - # Choose the lookup expression map based on the filter type - lookup_map = cls._get_filter_lookup_dict(existing_filter) - if lookup_map is None: - # Do not augment this filter type with more lookup expressions - continue - - # Get properties of the existing filter for later use - field_name = existing_filter.field_name - field = get_model_field(cls._meta.model, field_name) - - # Create new filters for each lookup expression in the map - for lookup_name, lookup_expr in lookup_map.items(): - new_filter_name = '{}__{}'.format(existing_filter_name, lookup_name) - - try: - if existing_filter_name in cls.declared_filters: - # The filter field has been explicity defined on the filterset class so we must manually - # create the new filter with the same type because there is no guarantee the defined type - # is the same as the default type for the field - resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid - new_filter = type(existing_filter)( - field_name=field_name, - lookup_expr=lookup_expr, - label=existing_filter.label, - exclude=existing_filter.exclude, - distinct=existing_filter.distinct, - **existing_filter.extra - ) - else: - # The filter field is listed in Meta.fields so we can safely rely on default behaviour - # Will raise FieldLookupError if the lookup is invalid - new_filter = cls.filter_for_field(field, field_name, lookup_expr) - except django_filters.exceptions.FieldLookupError: - # The filter could not be created because the lookup expression is not supported on the field - continue - - if lookup_name.startswith('n'): - # This is a negation filter which requires a queryset.exclude() clause - # Of course setting the negation of the existing filter's exclude attribute handles both cases - new_filter.exclude = not existing_filter.exclude - - new_filters[new_filter_name] = new_filter - - filters.update(new_filters) - return filters - - -class NameSlugSearchFilterSet(django_filters.FilterSet): - """ - A base class for adding the search method to models which only expose the `name` and `slug` fields - """ - q = django_filters.CharFilter( - method='search', - label='Search', - ) - - def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter( - models.Q(name__icontains=value) | - models.Q(slug__icontains=value) - ) diff --git a/netbox/utilities/filtersets.py b/netbox/utilities/filtersets.py new file mode 100644 index 000000000..0fb188d11 --- /dev/null +++ b/netbox/utilities/filtersets.py @@ -0,0 +1,190 @@ +import django_filters +from copy import deepcopy +from dcim.forms import MACAddressField +from django.db import models +from django_filters.utils import get_model_field, resolve_field + +from utilities.constants import ( + FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP, + FILTER_NUMERIC_BASED_LOOKUP_MAP +) +from utilities import filters + + +# +# FilterSets +# + +class BaseFilterSet(django_filters.FilterSet): + """ + A base filterset which provides common functionaly to all NetBox filtersets + """ + FILTER_DEFAULTS = deepcopy(django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS) + FILTER_DEFAULTS.update({ + models.AutoField: { + 'filter_class': filters.MultiValueNumberFilter + }, + models.CharField: { + 'filter_class': filters.MultiValueCharFilter + }, + models.DateField: { + 'filter_class': filters.MultiValueDateFilter + }, + models.DateTimeField: { + 'filter_class': filters.MultiValueDateTimeFilter + }, + models.DecimalField: { + 'filter_class': filters.MultiValueNumberFilter + }, + models.EmailField: { + 'filter_class': filters.MultiValueCharFilter + }, + models.FloatField: { + 'filter_class': filters.MultiValueNumberFilter + }, + models.IntegerField: { + 'filter_class': filters.MultiValueNumberFilter + }, + models.PositiveIntegerField: { + 'filter_class': filters.MultiValueNumberFilter + }, + models.PositiveSmallIntegerField: { + 'filter_class': filters.MultiValueNumberFilter + }, + models.SlugField: { + 'filter_class': filters.MultiValueCharFilter + }, + models.SmallIntegerField: { + 'filter_class': filters.MultiValueNumberFilter + }, + models.TimeField: { + 'filter_class': filters.MultiValueTimeFilter + }, + models.URLField: { + 'filter_class': filters.MultiValueCharFilter + }, + MACAddressField: { + 'filter_class': filters.MultiValueMACAddressFilter + }, + }) + + @staticmethod + def _get_filter_lookup_dict(existing_filter): + # Choose the lookup expression map based on the filter type + if isinstance(existing_filter, ( + filters.MultiValueDateFilter, + filters.MultiValueDateTimeFilter, + filters.MultiValueNumberFilter, + filters.MultiValueTimeFilter + )): + lookup_map = FILTER_NUMERIC_BASED_LOOKUP_MAP + + elif isinstance(existing_filter, ( + filters.TreeNodeMultipleChoiceFilter, + )): + # TreeNodeMultipleChoiceFilter only support negation but must maintain the `in` lookup expression + lookup_map = FILTER_TREENODE_NEGATION_LOOKUP_MAP + + elif isinstance(existing_filter, ( + django_filters.ModelChoiceFilter, + django_filters.ModelMultipleChoiceFilter, + filters.TagFilter + )) or existing_filter.extra.get('choices'): + # These filter types support only negation + lookup_map = FILTER_NEGATION_LOOKUP_MAP + + elif isinstance(existing_filter, ( + django_filters.filters.CharFilter, + django_filters.MultipleChoiceFilter, + filters.MultiValueCharFilter, + filters.MultiValueMACAddressFilter + )): + lookup_map = FILTER_CHAR_BASED_LOOKUP_MAP + + else: + lookup_map = None + + return lookup_map + + @classmethod + def get_filters(cls): + """ + Override filter generation to support dynamic lookup expressions for certain filter types. + + For specific filter types, new filters are created based on defined lookup expressions in + the form `__` + """ + filters = super().get_filters() + + new_filters = {} + for existing_filter_name, existing_filter in filters.items(): + # Loop over existing filters to extract metadata by which to create new filters + + # If the filter makes use of a custom filter method or lookup expression skip it + # as we cannot sanely handle these cases in a generic mannor + if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'in']: + continue + + # Choose the lookup expression map based on the filter type + lookup_map = cls._get_filter_lookup_dict(existing_filter) + if lookup_map is None: + # Do not augment this filter type with more lookup expressions + continue + + # Get properties of the existing filter for later use + field_name = existing_filter.field_name + field = get_model_field(cls._meta.model, field_name) + + # Create new filters for each lookup expression in the map + for lookup_name, lookup_expr in lookup_map.items(): + new_filter_name = '{}__{}'.format(existing_filter_name, lookup_name) + + try: + if existing_filter_name in cls.declared_filters: + # The filter field has been explicity defined on the filterset class so we must manually + # create the new filter with the same type because there is no guarantee the defined type + # is the same as the default type for the field + resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid + new_filter = type(existing_filter)( + field_name=field_name, + lookup_expr=lookup_expr, + label=existing_filter.label, + exclude=existing_filter.exclude, + distinct=existing_filter.distinct, + **existing_filter.extra + ) + else: + # The filter field is listed in Meta.fields so we can safely rely on default behaviour + # Will raise FieldLookupError if the lookup is invalid + new_filter = cls.filter_for_field(field, field_name, lookup_expr) + except django_filters.exceptions.FieldLookupError: + # The filter could not be created because the lookup expression is not supported on the field + continue + + if lookup_name.startswith('n'): + # This is a negation filter which requires a queryset.exclude() clause + # Of course setting the negation of the existing filter's exclude attribute handles both cases + new_filter.exclude = not existing_filter.exclude + + new_filters[new_filter_name] = new_filter + + filters.update(new_filters) + return filters + + +class NameSlugSearchFilterSet(django_filters.FilterSet): + """ + A base class for adding the search method to models which only expose the `name` and `slug` fields + """ + q = django_filters.CharFilter( + method='search', + label='Search', + ) + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + models.Q(name__icontains=value) | + models.Q(slug__icontains=value) + ) diff --git a/netbox/utilities/tests/test_filters.py b/netbox/utilities/tests/test_filters.py index 56eaabd4c..6d2826b70 100644 --- a/netbox/utilities/tests/test_filters.py +++ b/netbox/utilities/tests/test_filters.py @@ -13,9 +13,10 @@ from dcim.models import ( ) from extras.models import TaggedItem from utilities.filters import ( - BaseFilterSet, MACAddressFilter, MultiValueCharFilter, MultiValueDateFilter, MultiValueDateTimeFilter, - MultiValueNumberFilter, MultiValueTimeFilter, TagFilter, TreeNodeMultipleChoiceFilter, + MACAddressFilter, MultiValueCharFilter, MultiValueDateFilter, MultiValueDateTimeFilter, MultiValueNumberFilter, + MultiValueTimeFilter, TagFilter, TreeNodeMultipleChoiceFilter, ) +from utilities.filtersets import BaseFilterSet class TreeNodeMultipleChoiceFilterTest(TestCase): diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filters.py index 6d706b6cf..9ace5c49e 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filters.py @@ -4,10 +4,8 @@ from django.db.models import Q from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet, LocalConfigContextFilterSet from tenancy.filters import TenancyFilterSet -from utilities.filters import ( - BaseFilterSet, MultiValueMACAddressFilter, NameSlugSearchFilterSet, TagFilter, - TreeNodeMultipleChoiceFilter, -) +from utilities.filters import MultiValueMACAddressFilter, TagFilter, TreeNodeMultipleChoiceFilter +from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet from .choices import * from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface From c4e88fd11a7fe73a50e234e0a83a719cbd1cca8b Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Apr 2021 15:59:11 -0400 Subject: [PATCH 2/5] Consolidate FilterSet classes --- netbox/circuits/filters.py | 13 +- netbox/dcim/filters.py | 101 ++++---- netbox/extras/api/views.py | 24 +- netbox/extras/filters.py | 366 ---------------------------- netbox/extras/filtersets.py | 340 ++++++++++++++++++++++++++ netbox/extras/tests/test_filters.py | 2 +- netbox/extras/views.py | 16 +- netbox/ipam/filters.py | 23 +- netbox/secrets/filters.py | 7 +- netbox/tenancy/filters.py | 7 +- netbox/utilities/filtersets.py | 52 +++- netbox/virtualization/filters.py | 20 +- 12 files changed, 484 insertions(+), 487 deletions(-) create mode 100644 netbox/extras/filtersets.py diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index 7e0b1cade..6ff6bb104 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filters.py @@ -3,10 +3,9 @@ from django.db.models import Q from dcim.filters import CableTerminationFilterSet from dcim.models import Region, Site, SiteGroup -from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from tenancy.filters import TenancyFilterSet from utilities.filters import TagFilter, TreeNodeMultipleChoiceFilter -from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet +from utilities.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * from .models import * @@ -19,7 +18,7 @@ __all__ = ( ) -class ProviderFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class ProviderFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -79,7 +78,7 @@ class ProviderFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdated ) -class ProviderNetworkFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class ProviderNetworkFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -109,14 +108,14 @@ class ProviderNetworkFilterSet(BaseFilterSet, CustomFieldModelFilterSet, Created ).distinct() -class CircuitTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class CircuitTypeFilterSet(OrganizationalModelFilterSet): class Meta: model = CircuitType fields = ['id', 'name', 'slug'] -class CircuitFilterSet(BaseFilterSet, CustomFieldModelFilterSet, TenancyFilterSet, CreatedUpdatedFilterSet): +class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -206,7 +205,7 @@ class CircuitFilterSet(BaseFilterSet, CustomFieldModelFilterSet, TenancyFilterSe ).distinct() -class CircuitTerminationFilterSet(BaseFilterSet, CreatedUpdatedFilterSet, CableTerminationFilterSet): +class CircuitTerminationFilterSet(ChangeLoggedModelFilterSet, CableTerminationFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index 777ca5884..a45900466 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -1,14 +1,16 @@ import django_filters from django.contrib.auth.models import User -from extras.filters import CustomFieldModelFilterSet, LocalConfigContextFilterSet, CreatedUpdatedFilterSet +from extras.filtersets import LocalConfigContextFilterSet from tenancy.filters import TenancyFilterSet from tenancy.models import Tenant from utilities.choices import ColorChoices from utilities.filters import ( MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, TagFilter, TreeNodeMultipleChoiceFilter, ) -from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet +from utilities.filtersets import ( + BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet, +) from virtualization.models import Cluster from .choices import * from .constants import * @@ -57,7 +59,7 @@ __all__ = ( ) -class RegionFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class RegionFilterSet(OrganizationalModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=Region.objects.all(), label='Parent region (ID)', @@ -74,7 +76,7 @@ class RegionFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilt fields = ['id', 'name', 'slug', 'description'] -class SiteGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class SiteGroupFilterSet(OrganizationalModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=SiteGroup.objects.all(), label='Parent site group (ID)', @@ -91,7 +93,7 @@ class SiteGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedF fields = ['id', 'name', 'slug', 'description'] -class SiteFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class SiteFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -154,7 +156,7 @@ class SiteFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, return queryset.filter(qs_filter) -class LocationFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class LocationFilterSet(OrganizationalModelFilterSet): region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', @@ -218,14 +220,14 @@ class LocationFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFi ) -class RackRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class RackRoleFilterSet(OrganizationalModelFilterSet): class Meta: model = RackRole fields = ['id', 'name', 'slug', 'color'] -class RackFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -323,7 +325,7 @@ class RackFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, ) -class RackReservationFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class RackReservationFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -383,14 +385,14 @@ class RackReservationFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModel ) -class ManufacturerFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class ManufacturerFilterSet(OrganizationalModelFilterSet): class Meta: model = Manufacturer fields = ['id', 'name', 'slug', 'description'] -class DeviceTypeFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class DeviceTypeFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -476,7 +478,7 @@ class DeviceTypeFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdat return queryset.exclude(devicebaytemplates__isnull=value) -class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class DeviceTypeComponentFilterSet(django_filters.FilterSet): devicetype_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceType.objects.all(), field_name='device_type_id', @@ -484,28 +486,28 @@ class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet, CreatedUpdatedFilter ) -class ConsolePortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class ConsolePortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): class Meta: model = ConsolePortTemplate fields = ['id', 'name', 'type'] -class ConsoleServerPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class ConsoleServerPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): class Meta: model = ConsoleServerPortTemplate fields = ['id', 'name', 'type'] -class PowerPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class PowerPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): class Meta: model = PowerPortTemplate fields = ['id', 'name', 'type', 'maximum_draw', 'allocated_draw'] -class PowerOutletTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class PowerOutletTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): feed_leg = django_filters.MultipleChoiceFilter( choices=PowerOutletFeedLegChoices, null_value=None @@ -516,7 +518,7 @@ class PowerOutletTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): fields = ['id', 'name', 'type', 'feed_leg'] -class InterfaceTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): type = django_filters.MultipleChoiceFilter( choices=InterfaceTypeChoices, null_value=None @@ -527,7 +529,7 @@ class InterfaceTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): fields = ['id', 'name', 'type', 'mgmt_only'] -class FrontPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, null_value=None @@ -538,7 +540,7 @@ class FrontPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): fields = ['id', 'name', 'type'] -class RearPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, null_value=None @@ -549,21 +551,21 @@ class RearPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): fields = ['id', 'name', 'type', 'positions'] -class DeviceBayTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): +class DeviceBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): class Meta: model = DeviceBayTemplate fields = ['id', 'name'] -class DeviceRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class DeviceRoleFilterSet(OrganizationalModelFilterSet): class Meta: model = DeviceRole fields = ['id', 'name', 'slug', 'color', 'vm_role'] -class PlatformFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class PlatformFilterSet(OrganizationalModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer', queryset=Manufacturer.objects.all(), @@ -581,13 +583,7 @@ class PlatformFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFi fields = ['id', 'name', 'slug', 'napalm_driver', 'description'] -class DeviceFilterSet( - BaseFilterSet, - TenancyFilterSet, - LocalConfigContextFilterSet, - CustomFieldModelFilterSet, - CreatedUpdatedFilterSet -): +class DeviceFilterSet(PrimaryModelFilterSet, TenancyFilterSet, LocalConfigContextFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -792,7 +788,7 @@ class DeviceFilterSet( return queryset.exclude(devicebays__isnull=value) -class DeviceComponentFilterSet(CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class DeviceComponentFilterSet(django_filters.FilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -876,7 +872,7 @@ class PathEndpointFilterSet(django_filters.FilterSet): return queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False)) -class ConsolePortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): +class ConsolePortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=ConsolePortTypeChoices, null_value=None @@ -887,12 +883,7 @@ class ConsolePortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTermina fields = ['id', 'name', 'label', 'description'] -class ConsoleServerPortFilterSet( - BaseFilterSet, - DeviceComponentFilterSet, - CableTerminationFilterSet, - PathEndpointFilterSet -): +class ConsoleServerPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=ConsolePortTypeChoices, null_value=None @@ -903,7 +894,7 @@ class ConsoleServerPortFilterSet( fields = ['id', 'name', 'label', 'description'] -class PowerPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): +class PowerPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=PowerPortTypeChoices, null_value=None @@ -914,7 +905,7 @@ class PowerPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminati fields = ['id', 'name', 'label', 'maximum_draw', 'allocated_draw', 'description'] -class PowerOutletFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): +class PowerOutletFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): type = django_filters.MultipleChoiceFilter( choices=PowerOutletTypeChoices, null_value=None @@ -929,7 +920,7 @@ class PowerOutletFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTermina fields = ['id', 'name', 'label', 'feed_leg', 'description'] -class InterfaceFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): +class InterfaceFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1027,7 +1018,7 @@ class InterfaceFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminati }.get(value, queryset.none()) -class FrontPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet): +class FrontPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, null_value=None @@ -1038,7 +1029,7 @@ class FrontPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminati fields = ['id', 'name', 'label', 'type', 'description'] -class RearPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet): +class RearPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet): type = django_filters.MultipleChoiceFilter( choices=PortTypeChoices, null_value=None @@ -1049,14 +1040,14 @@ class RearPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminatio fields = ['id', 'name', 'label', 'type', 'positions', 'description'] -class DeviceBayFilterSet(BaseFilterSet, DeviceComponentFilterSet): +class DeviceBayFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet): class Meta: model = DeviceBay fields = ['id', 'name', 'label', 'description'] -class InventoryItemFilterSet(BaseFilterSet, DeviceComponentFilterSet): +class InventoryItemFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1129,7 +1120,7 @@ class InventoryItemFilterSet(BaseFilterSet, DeviceComponentFilterSet): return queryset.filter(qs_filter) -class VirtualChassisFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class VirtualChassisFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1209,7 +1200,7 @@ class VirtualChassisFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedU return queryset.filter(qs_filter).distinct() -class CableFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class CableFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1273,7 +1264,7 @@ class CableFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFil return queryset -class ConnectionFilterSet: +class ConnectionFilterSet(BaseFilterSet): def filter_site(self, queryset, name, value): if not value.strip(): @@ -1286,7 +1277,7 @@ class ConnectionFilterSet: return queryset.filter(**{f'{name}__in': value}) -class ConsoleConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): +class ConsoleConnectionFilterSet(ConnectionFilterSet): site = django_filters.CharFilter( method='filter_site', label='Site (slug)', @@ -1304,7 +1295,7 @@ class ConsoleConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): fields = ['name'] -class PowerConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): +class PowerConnectionFilterSet(ConnectionFilterSet): site = django_filters.CharFilter( method='filter_site', label='Site (slug)', @@ -1322,7 +1313,7 @@ class PowerConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): fields = ['name'] -class InterfaceConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): +class InterfaceConnectionFilterSet(ConnectionFilterSet): site = django_filters.CharFilter( method='filter_site', label='Site (slug)', @@ -1340,7 +1331,7 @@ class InterfaceConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): fields = [] -class PowerPanelFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class PowerPanelFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1402,13 +1393,7 @@ class PowerPanelFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdat return queryset.filter(qs_filter) -class PowerFeedFilterSet( - BaseFilterSet, - CableTerminationFilterSet, - PathEndpointFilterSet, - CustomFieldModelFilterSet, - CreatedUpdatedFilterSet -): +class PowerFeedFilterSet(PrimaryModelFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index cee5146a6..7e6c97782 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -9,7 +9,7 @@ from rest_framework.routers import APIRootView from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet from rq import Worker -from extras import filters +from extras import filtersets from extras.choices import JobResultStatusChoices from extras.models import * from extras.models import CustomField @@ -61,7 +61,7 @@ class WebhookViewSet(ModelViewSet): metadata_class = ContentTypeMetadata queryset = Webhook.objects.all() serializer_class = serializers.WebhookSerializer - filterset_class = filters.WebhookFilterSet + filterset_class = filtersets.WebhookFilterSet # @@ -72,7 +72,7 @@ class CustomFieldViewSet(ModelViewSet): metadata_class = ContentTypeMetadata queryset = CustomField.objects.all() serializer_class = serializers.CustomFieldSerializer - filterset_class = filters.CustomFieldFilterSet + filterset_class = filtersets.CustomFieldFilterSet class CustomFieldModelViewSet(ModelViewSet): @@ -101,7 +101,7 @@ class CustomLinkViewSet(ModelViewSet): metadata_class = ContentTypeMetadata queryset = CustomLink.objects.all() serializer_class = serializers.CustomLinkSerializer - filterset_class = filters.CustomLinkFilterSet + filterset_class = filtersets.CustomLinkFilterSet # @@ -112,7 +112,7 @@ class ExportTemplateViewSet(ModelViewSet): metadata_class = ContentTypeMetadata queryset = ExportTemplate.objects.all() serializer_class = serializers.ExportTemplateSerializer - filterset_class = filters.ExportTemplateFilterSet + filterset_class = filtersets.ExportTemplateFilterSet # @@ -124,7 +124,7 @@ class TagViewSet(ModelViewSet): tagged_items=count_related(TaggedItem, 'tag') ) serializer_class = serializers.TagSerializer - filterset_class = filters.TagFilterSet + filterset_class = filtersets.TagFilterSet # @@ -135,7 +135,7 @@ class ImageAttachmentViewSet(ModelViewSet): metadata_class = ContentTypeMetadata queryset = ImageAttachment.objects.all() serializer_class = serializers.ImageAttachmentSerializer - filterset_class = filters.ImageAttachmentFilterSet + filterset_class = filtersets.ImageAttachmentFilterSet # @@ -146,7 +146,7 @@ class JournalEntryViewSet(ModelViewSet): metadata_class = ContentTypeMetadata queryset = JournalEntry.objects.all() serializer_class = serializers.JournalEntrySerializer - filterset_class = filters.JournalEntryFilterSet + filterset_class = filtersets.JournalEntryFilterSet # @@ -158,7 +158,7 @@ class ConfigContextViewSet(ModelViewSet): 'regions', 'site_groups', 'sites', 'roles', 'platforms', 'tenant_groups', 'tenants', ) serializer_class = serializers.ConfigContextSerializer - filterset_class = filters.ConfigContextFilterSet + filterset_class = filtersets.ConfigContextFilterSet # @@ -358,7 +358,7 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet): metadata_class = ContentTypeMetadata queryset = ObjectChange.objects.prefetch_related('user') serializer_class = serializers.ObjectChangeSerializer - filterset_class = filters.ObjectChangeFilterSet + filterset_class = filtersets.ObjectChangeFilterSet # @@ -371,7 +371,7 @@ class JobResultViewSet(ReadOnlyModelViewSet): """ queryset = JobResult.objects.prefetch_related('user') serializer_class = serializers.JobResultSerializer - filterset_class = filters.JobResultFilterSet + filterset_class = filtersets.JobResultFilterSet # @@ -384,4 +384,4 @@ class ContentTypeViewSet(ReadOnlyModelViewSet): """ queryset = ContentType.objects.order_by('app_label', 'model') serializer_class = serializers.ContentTypeSerializer - filterset_class = filters.ContentTypeFilterSet + filterset_class = filtersets.ContentTypeFilterSet diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index 9105da81f..dff12aa91 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -1,32 +1,10 @@ import django_filters -from django.contrib.auth.models import User -from django.contrib.contenttypes.models import ContentType -from django.db.models import Q from django.forms import DateField, IntegerField, NullBooleanField -from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup -from tenancy.models import Tenant, TenantGroup -from utilities.filtersets import BaseFilterSet -from utilities.filters import ContentTypeFilter -from virtualization.models import Cluster, ClusterGroup from .choices import * -from .models import * - __all__ = ( - 'ConfigContextFilterSet', - 'ContentTypeFilterSet', - 'CreatedUpdatedFilterSet', 'CustomFieldFilter', - 'CustomLinkFilterSet', - 'CustomFieldModelFilterSet', - 'ExportTemplateFilterSet', - 'ImageAttachmentFilterSet', - 'JournalEntryFilterSet', - 'LocalConfigContextFilterSet', - 'ObjectChangeFilterSet', - 'TagFilterSet', - 'WebhookFilterSet', ) EXACT_FILTER_TYPES = ( @@ -37,41 +15,6 @@ EXACT_FILTER_TYPES = ( ) -class CreatedUpdatedFilterSet(django_filters.FilterSet): - created = django_filters.DateFilter() - created__gte = django_filters.DateFilter( - field_name='created', - lookup_expr='gte' - ) - created__lte = django_filters.DateFilter( - field_name='created', - lookup_expr='lte' - ) - last_updated = django_filters.DateTimeFilter() - last_updated__gte = django_filters.DateTimeFilter( - field_name='last_updated', - lookup_expr='gte' - ) - last_updated__lte = django_filters.DateTimeFilter( - field_name='last_updated', - lookup_expr='lte' - ) - - -class WebhookFilterSet(BaseFilterSet): - content_types = ContentTypeFilter() - http_method = django_filters.MultipleChoiceFilter( - choices=WebhookHttpMethodChoices - ) - - class Meta: - model = Webhook - fields = [ - 'id', 'content_types', 'name', 'type_create', 'type_update', 'type_delete', 'payload_url', 'enabled', - 'http_method', 'http_content_type', 'secret', 'ssl_verification', 'ca_file_path', - ] - - class CustomFieldFilter(django_filters.Filter): """ Filter objects by the presence of a CustomFieldValue. The filter's name is used as the CustomField name. @@ -93,312 +36,3 @@ class CustomFieldFilter(django_filters.Filter): if custom_field.type not in EXACT_FILTER_TYPES: if custom_field.filter_logic == CustomFieldFilterLogicChoices.FILTER_LOOSE: self.lookup_expr = 'icontains' - - -class CustomFieldModelFilterSet(django_filters.FilterSet): - """ - Dynamically add a Filter for each CustomField applicable to the parent model. - """ - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - custom_fields = CustomField.objects.filter( - content_types=ContentType.objects.get_for_model(self._meta.model) - ).exclude( - filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED - ) - for cf in custom_fields: - self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(field_name=cf.name, custom_field=cf) - - -class CustomFieldFilterSet(django_filters.FilterSet): - content_types = ContentTypeFilter() - - class Meta: - model = CustomField - fields = ['id', 'content_types', 'name', 'required', 'filter_logic', 'weight'] - - -class CustomLinkFilterSet(BaseFilterSet): - - class Meta: - model = CustomLink - fields = ['id', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'new_window'] - - -class ExportTemplateFilterSet(BaseFilterSet): - - class Meta: - model = ExportTemplate - fields = ['id', 'content_type', 'name'] - - -class ImageAttachmentFilterSet(BaseFilterSet): - content_type = ContentTypeFilter() - - class Meta: - model = ImageAttachment - fields = ['id', 'content_type_id', 'object_id', 'name'] - - -class JournalEntryFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): - q = django_filters.CharFilter( - method='search', - label='Search', - ) - created = django_filters.DateTimeFromToRangeFilter() - assigned_object_type = ContentTypeFilter() - created_by_id = django_filters.ModelMultipleChoiceFilter( - queryset=User.objects.all(), - label='User (ID)', - ) - created_by = django_filters.ModelMultipleChoiceFilter( - field_name='created_by__username', - queryset=User.objects.all(), - to_field_name='username', - label='User (name)', - ) - kind = django_filters.MultipleChoiceFilter( - choices=JournalEntryKindChoices - ) - - class Meta: - model = JournalEntry - fields = ['id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind'] - - def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter(comments__icontains=value) - - -class TagFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): - q = django_filters.CharFilter( - method='search', - label='Search', - ) - - class Meta: - model = Tag - fields = ['id', 'name', 'slug', 'color'] - - def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter( - Q(name__icontains=value) | - Q(slug__icontains=value) - ) - - -class ConfigContextFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): - q = django_filters.CharFilter( - method='search', - label='Search', - ) - region_id = django_filters.ModelMultipleChoiceFilter( - field_name='regions', - queryset=Region.objects.all(), - label='Region', - ) - region = django_filters.ModelMultipleChoiceFilter( - field_name='regions__slug', - queryset=Region.objects.all(), - to_field_name='slug', - label='Region (slug)', - ) - site_group = django_filters.ModelMultipleChoiceFilter( - field_name='site_groups__slug', - queryset=SiteGroup.objects.all(), - to_field_name='slug', - label='Site group (slug)', - ) - site_group_id = django_filters.ModelMultipleChoiceFilter( - field_name='site_groups', - queryset=SiteGroup.objects.all(), - label='Site group', - ) - site_id = django_filters.ModelMultipleChoiceFilter( - field_name='sites', - queryset=Site.objects.all(), - label='Site', - ) - site = django_filters.ModelMultipleChoiceFilter( - field_name='sites__slug', - queryset=Site.objects.all(), - to_field_name='slug', - label='Site (slug)', - ) - device_type_id = django_filters.ModelMultipleChoiceFilter( - field_name='device_types', - queryset=DeviceType.objects.all(), - label='Device type', - ) - role_id = django_filters.ModelMultipleChoiceFilter( - field_name='roles', - queryset=DeviceRole.objects.all(), - label='Role', - ) - role = django_filters.ModelMultipleChoiceFilter( - field_name='roles__slug', - queryset=DeviceRole.objects.all(), - to_field_name='slug', - label='Role (slug)', - ) - platform_id = django_filters.ModelMultipleChoiceFilter( - field_name='platforms', - queryset=Platform.objects.all(), - label='Platform', - ) - platform = django_filters.ModelMultipleChoiceFilter( - field_name='platforms__slug', - queryset=Platform.objects.all(), - to_field_name='slug', - label='Platform (slug)', - ) - cluster_group_id = django_filters.ModelMultipleChoiceFilter( - field_name='cluster_groups', - queryset=ClusterGroup.objects.all(), - label='Cluster group', - ) - cluster_group = django_filters.ModelMultipleChoiceFilter( - field_name='cluster_groups__slug', - queryset=ClusterGroup.objects.all(), - to_field_name='slug', - label='Cluster group (slug)', - ) - cluster_id = django_filters.ModelMultipleChoiceFilter( - field_name='clusters', - queryset=Cluster.objects.all(), - label='Cluster', - ) - tenant_group_id = django_filters.ModelMultipleChoiceFilter( - field_name='tenant_groups', - queryset=TenantGroup.objects.all(), - label='Tenant group', - ) - tenant_group = django_filters.ModelMultipleChoiceFilter( - field_name='tenant_groups__slug', - queryset=TenantGroup.objects.all(), - to_field_name='slug', - label='Tenant group (slug)', - ) - tenant_id = django_filters.ModelMultipleChoiceFilter( - field_name='tenants', - queryset=Tenant.objects.all(), - label='Tenant', - ) - tenant = django_filters.ModelMultipleChoiceFilter( - field_name='tenants__slug', - queryset=Tenant.objects.all(), - to_field_name='slug', - label='Tenant (slug)', - ) - tag = django_filters.ModelMultipleChoiceFilter( - field_name='tags__slug', - queryset=Tag.objects.all(), - to_field_name='slug', - label='Tag (slug)', - ) - - class Meta: - model = ConfigContext - fields = ['id', 'name', 'is_active'] - - def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter( - Q(name__icontains=value) | - Q(description__icontains=value) | - Q(data__icontains=value) - ) - - -# -# Filter for Local Config Context Data -# - -class LocalConfigContextFilterSet(django_filters.FilterSet): - local_context_data = django_filters.BooleanFilter( - method='_local_context_data', - label='Has local config context data', - ) - - def _local_context_data(self, queryset, name, value): - return queryset.exclude(local_context_data__isnull=value) - - -class ObjectChangeFilterSet(BaseFilterSet): - q = django_filters.CharFilter( - method='search', - label='Search', - ) - time = django_filters.DateTimeFromToRangeFilter() - changed_object_type = ContentTypeFilter() - user_id = django_filters.ModelMultipleChoiceFilter( - queryset=User.objects.all(), - label='User (ID)', - ) - user = django_filters.ModelMultipleChoiceFilter( - field_name='user__username', - queryset=User.objects.all(), - to_field_name='username', - label='User name', - ) - - class Meta: - model = ObjectChange - fields = [ - 'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id', - 'object_repr', - ] - - def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter( - Q(user_name__icontains=value) | - Q(object_repr__icontains=value) - ) - - -# -# Job Results -# - -class JobResultFilterSet(BaseFilterSet): - q = django_filters.CharFilter( - method='search', - label='Search', - ) - created = django_filters.DateTimeFilter() - completed = django_filters.DateTimeFilter() - status = django_filters.MultipleChoiceFilter( - choices=JobResultStatusChoices, - null_value=None - ) - - class Meta: - model = JobResult - fields = [ - 'id', 'created', 'completed', 'status', 'user', 'obj_type', 'name' - ] - - def search(self, queryset, name, value): - if not value.strip(): - return queryset - return queryset.filter( - Q(user__username__icontains=value) - ) - - -# -# ContentTypes -# - -class ContentTypeFilterSet(django_filters.FilterSet): - - class Meta: - model = ContentType - fields = ['id', 'app_label', 'model'] diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py new file mode 100644 index 000000000..1451a34c0 --- /dev/null +++ b/netbox/extras/filtersets.py @@ -0,0 +1,340 @@ +import django_filters +from django.contrib.auth.models import User +from django.contrib.contenttypes.models import ContentType +from django.db.models import Q + +from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup +from tenancy.models import Tenant, TenantGroup +from utilities.filters import ContentTypeFilter +from utilities.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet +from virtualization.models import Cluster, ClusterGroup +from .choices import * +from .models import * + + +__all__ = ( + 'ConfigContextFilterSet', + 'ContentTypeFilterSet', + 'CustomLinkFilterSet', + 'ExportTemplateFilterSet', + 'ImageAttachmentFilterSet', + 'JournalEntryFilterSet', + 'LocalConfigContextFilterSet', + 'ObjectChangeFilterSet', + 'TagFilterSet', + 'WebhookFilterSet', +) + +EXACT_FILTER_TYPES = ( + CustomFieldTypeChoices.TYPE_BOOLEAN, + CustomFieldTypeChoices.TYPE_DATE, + CustomFieldTypeChoices.TYPE_INTEGER, + CustomFieldTypeChoices.TYPE_SELECT, +) + + +class WebhookFilterSet(BaseFilterSet): + content_types = ContentTypeFilter() + http_method = django_filters.MultipleChoiceFilter( + choices=WebhookHttpMethodChoices + ) + + class Meta: + model = Webhook + fields = [ + 'id', 'content_types', 'name', 'type_create', 'type_update', 'type_delete', 'payload_url', 'enabled', + 'http_method', 'http_content_type', 'secret', 'ssl_verification', 'ca_file_path', + ] + + +class CustomFieldFilterSet(django_filters.FilterSet): + content_types = ContentTypeFilter() + + class Meta: + model = CustomField + fields = ['id', 'content_types', 'name', 'required', 'filter_logic', 'weight'] + + +class CustomLinkFilterSet(BaseFilterSet): + + class Meta: + model = CustomLink + fields = ['id', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'new_window'] + + +class ExportTemplateFilterSet(BaseFilterSet): + + class Meta: + model = ExportTemplate + fields = ['id', 'content_type', 'name'] + + +class ImageAttachmentFilterSet(BaseFilterSet): + content_type = ContentTypeFilter() + + class Meta: + model = ImageAttachment + fields = ['id', 'content_type_id', 'object_id', 'name'] + + +class JournalEntryFilterSet(ChangeLoggedModelFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + created = django_filters.DateTimeFromToRangeFilter() + assigned_object_type = ContentTypeFilter() + created_by_id = django_filters.ModelMultipleChoiceFilter( + queryset=User.objects.all(), + label='User (ID)', + ) + created_by = django_filters.ModelMultipleChoiceFilter( + field_name='created_by__username', + queryset=User.objects.all(), + to_field_name='username', + label='User (name)', + ) + kind = django_filters.MultipleChoiceFilter( + choices=JournalEntryKindChoices + ) + + class Meta: + model = JournalEntry + fields = ['id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind'] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter(comments__icontains=value) + + +class TagFilterSet(ChangeLoggedModelFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + + class Meta: + model = Tag + fields = ['id', 'name', 'slug', 'color'] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(name__icontains=value) | + Q(slug__icontains=value) + ) + + +class ConfigContextFilterSet(ChangeLoggedModelFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + region_id = django_filters.ModelMultipleChoiceFilter( + field_name='regions', + queryset=Region.objects.all(), + label='Region', + ) + region = django_filters.ModelMultipleChoiceFilter( + field_name='regions__slug', + queryset=Region.objects.all(), + to_field_name='slug', + label='Region (slug)', + ) + site_group = django_filters.ModelMultipleChoiceFilter( + field_name='site_groups__slug', + queryset=SiteGroup.objects.all(), + to_field_name='slug', + label='Site group (slug)', + ) + site_group_id = django_filters.ModelMultipleChoiceFilter( + field_name='site_groups', + queryset=SiteGroup.objects.all(), + label='Site group', + ) + site_id = django_filters.ModelMultipleChoiceFilter( + field_name='sites', + queryset=Site.objects.all(), + label='Site', + ) + site = django_filters.ModelMultipleChoiceFilter( + field_name='sites__slug', + queryset=Site.objects.all(), + to_field_name='slug', + label='Site (slug)', + ) + device_type_id = django_filters.ModelMultipleChoiceFilter( + field_name='device_types', + queryset=DeviceType.objects.all(), + label='Device type', + ) + role_id = django_filters.ModelMultipleChoiceFilter( + field_name='roles', + queryset=DeviceRole.objects.all(), + label='Role', + ) + role = django_filters.ModelMultipleChoiceFilter( + field_name='roles__slug', + queryset=DeviceRole.objects.all(), + to_field_name='slug', + label='Role (slug)', + ) + platform_id = django_filters.ModelMultipleChoiceFilter( + field_name='platforms', + queryset=Platform.objects.all(), + label='Platform', + ) + platform = django_filters.ModelMultipleChoiceFilter( + field_name='platforms__slug', + queryset=Platform.objects.all(), + to_field_name='slug', + label='Platform (slug)', + ) + cluster_group_id = django_filters.ModelMultipleChoiceFilter( + field_name='cluster_groups', + queryset=ClusterGroup.objects.all(), + label='Cluster group', + ) + cluster_group = django_filters.ModelMultipleChoiceFilter( + field_name='cluster_groups__slug', + queryset=ClusterGroup.objects.all(), + to_field_name='slug', + label='Cluster group (slug)', + ) + cluster_id = django_filters.ModelMultipleChoiceFilter( + field_name='clusters', + queryset=Cluster.objects.all(), + label='Cluster', + ) + tenant_group_id = django_filters.ModelMultipleChoiceFilter( + field_name='tenant_groups', + queryset=TenantGroup.objects.all(), + label='Tenant group', + ) + tenant_group = django_filters.ModelMultipleChoiceFilter( + field_name='tenant_groups__slug', + queryset=TenantGroup.objects.all(), + to_field_name='slug', + label='Tenant group (slug)', + ) + tenant_id = django_filters.ModelMultipleChoiceFilter( + field_name='tenants', + queryset=Tenant.objects.all(), + label='Tenant', + ) + tenant = django_filters.ModelMultipleChoiceFilter( + field_name='tenants__slug', + queryset=Tenant.objects.all(), + to_field_name='slug', + label='Tenant (slug)', + ) + tag = django_filters.ModelMultipleChoiceFilter( + field_name='tags__slug', + queryset=Tag.objects.all(), + to_field_name='slug', + label='Tag (slug)', + ) + + class Meta: + model = ConfigContext + fields = ['id', 'name', 'is_active'] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(name__icontains=value) | + Q(description__icontains=value) | + Q(data__icontains=value) + ) + + +# +# Filter for Local Config Context Data +# + +class LocalConfigContextFilterSet(django_filters.FilterSet): + local_context_data = django_filters.BooleanFilter( + method='_local_context_data', + label='Has local config context data', + ) + + def _local_context_data(self, queryset, name, value): + return queryset.exclude(local_context_data__isnull=value) + + +class ObjectChangeFilterSet(BaseFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + time = django_filters.DateTimeFromToRangeFilter() + changed_object_type = ContentTypeFilter() + user_id = django_filters.ModelMultipleChoiceFilter( + queryset=User.objects.all(), + label='User (ID)', + ) + user = django_filters.ModelMultipleChoiceFilter( + field_name='user__username', + queryset=User.objects.all(), + to_field_name='username', + label='User name', + ) + + class Meta: + model = ObjectChange + fields = [ + 'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id', + 'object_repr', + ] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(user_name__icontains=value) | + Q(object_repr__icontains=value) + ) + + +# +# Job Results +# + +class JobResultFilterSet(BaseFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + created = django_filters.DateTimeFilter() + completed = django_filters.DateTimeFilter() + status = django_filters.MultipleChoiceFilter( + choices=JobResultStatusChoices, + null_value=None + ) + + class Meta: + model = JobResult + fields = [ + 'id', 'created', 'completed', 'status', 'user', 'obj_type', 'name' + ] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(user__username__icontains=value) + ) + + +# +# ContentTypes +# + +class ContentTypeFilterSet(django_filters.FilterSet): + + class Meta: + model = ContentType + fields = ['id', 'app_label', 'model'] diff --git a/netbox/extras/tests/test_filters.py b/netbox/extras/tests/test_filters.py index bb78c4daf..bd4f1c246 100644 --- a/netbox/extras/tests/test_filters.py +++ b/netbox/extras/tests/test_filters.py @@ -6,7 +6,7 @@ from django.test import TestCase from dcim.models import DeviceRole, DeviceType, Manufacturer, Platform, Rack, Region, Site, SiteGroup from extras.choices import JournalEntryKindChoices, ObjectChangeActionChoices -from extras.filters import * +from extras.filtersets import * from extras.models import * from ipam.models import IPAddress from tenancy.models import Tenant, TenantGroup diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 4cda84d99..3f86c98d2 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -13,7 +13,7 @@ from utilities.forms import ConfirmationForm from utilities.tables import paginate_table from utilities.utils import copy_safe_request, count_related, shallow_compare_dict from utilities.views import ContentTypePermissionRequiredMixin -from . import filters, forms, tables +from . import filtersets, forms, tables from .choices import JobResultStatusChoices from .models import ConfigContext, ImageAttachment, JournalEntry, ObjectChange, JobResult, Tag, TaggedItem from .reports import get_report, get_reports, run_report @@ -28,7 +28,7 @@ class TagListView(generic.ObjectListView): queryset = Tag.objects.annotate( items=count_related(TaggedItem, 'tag') ) - filterset = filters.TagFilterSet + filterset = filtersets.TagFilterSet filterset_form = forms.TagFilterForm table = tables.TagTable @@ -94,7 +94,7 @@ class TagBulkDeleteView(generic.BulkDeleteView): class ConfigContextListView(generic.ObjectListView): queryset = ConfigContext.objects.all() - filterset = filters.ConfigContextFilterSet + filterset = filtersets.ConfigContextFilterSet filterset_form = forms.ConfigContextFilterForm table = tables.ConfigContextTable action_buttons = ('add',) @@ -127,7 +127,7 @@ class ConfigContextEditView(generic.ObjectEditView): class ConfigContextBulkEditView(generic.BulkEditView): queryset = ConfigContext.objects.all() - filterset = filters.ConfigContextFilterSet + filterset = filtersets.ConfigContextFilterSet table = tables.ConfigContextTable form = forms.ConfigContextBulkEditForm @@ -173,7 +173,7 @@ class ObjectConfigContextView(generic.ObjectView): class ObjectChangeListView(generic.ObjectListView): queryset = ObjectChange.objects.all() - filterset = filters.ObjectChangeFilterSet + filterset = filtersets.ObjectChangeFilterSet filterset_form = forms.ObjectChangeFilterForm table = tables.ObjectChangeTable template_name = 'extras/objectchange_list.html' @@ -300,7 +300,7 @@ class ImageAttachmentDeleteView(generic.ObjectDeleteView): class JournalEntryListView(generic.ObjectListView): queryset = JournalEntry.objects.all() - filterset = filters.JournalEntryFilterSet + filterset = filtersets.JournalEntryFilterSet filterset_form = forms.JournalEntryFilterForm table = tables.JournalEntryTable action_buttons = ('export',) @@ -338,14 +338,14 @@ class JournalEntryDeleteView(generic.ObjectDeleteView): class JournalEntryBulkEditView(generic.BulkEditView): queryset = JournalEntry.objects.prefetch_related('created_by') - filterset = filters.JournalEntryFilterSet + filterset = filtersets.JournalEntryFilterSet table = tables.JournalEntryTable form = forms.JournalEntryBulkEditForm class JournalEntryBulkDeleteView(generic.BulkDeleteView): queryset = JournalEntry.objects.prefetch_related('created_by') - filterset = filters.JournalEntryFilterSet + filterset = filtersets.JournalEntryFilterSet table = tables.JournalEntryTable diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index af047424f..4ecea50af 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -6,13 +6,12 @@ from django.db.models import Q from netaddr.core import AddrFormatError from dcim.models import Device, Interface, Region, Site, SiteGroup -from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from tenancy.filters import TenancyFilterSet from utilities.filters import ( ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TagFilter, TreeNodeMultipleChoiceFilter, ) -from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet +from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from virtualization.models import VirtualMachine, VMInterface from .choices import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF @@ -32,7 +31,7 @@ __all__ = ( ) -class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class VRFFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -75,7 +74,7 @@ class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, C fields = ['id', 'name', 'rd', 'enforce_unique'] -class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class RouteTargetFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -117,14 +116,14 @@ class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilt fields = ['id', 'name'] -class RIRFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class RIRFilterSet(OrganizationalModelFilterSet): class Meta: model = RIR fields = ['id', 'name', 'slug', 'is_private', 'description'] -class AggregateFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -174,7 +173,7 @@ class AggregateFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilter return queryset.none() -class RoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class RoleFilterSet(OrganizationalModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -185,7 +184,7 @@ class RoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilter fields = ['id', 'name', 'slug'] -class PrefixFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class PrefixFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -370,7 +369,7 @@ class PrefixFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet ) -class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -536,7 +535,7 @@ class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilter return queryset.exclude(assigned_object_id__isnull=value) -class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class VLANGroupFilterSet(OrganizationalModelFilterSet): scope_type = ContentTypeFilter() region = django_filters.NumberFilter( method='filter_scope' @@ -571,7 +570,7 @@ class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedF ) -class VLANFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -667,7 +666,7 @@ class VLANFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, return queryset.get_for_virtualmachine(value) -class ServiceFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): +class ServiceFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/secrets/filters.py b/netbox/secrets/filters.py index ec41ac364..6571c60f9 100644 --- a/netbox/secrets/filters.py +++ b/netbox/secrets/filters.py @@ -2,9 +2,8 @@ import django_filters from django.db.models import Q from dcim.models import Device -from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from utilities.filters import TagFilter -from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet +from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from virtualization.models import VirtualMachine from .models import Secret, SecretRole @@ -15,14 +14,14 @@ __all__ = ( ) -class SecretRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class SecretRoleFilterSet(OrganizationalModelFilterSet): class Meta: model = SecretRole fields = ['id', 'name', 'slug'] -class SecretFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class SecretFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filters.py index 8d43a3794..9cbaed170 100644 --- a/netbox/tenancy/filters.py +++ b/netbox/tenancy/filters.py @@ -1,9 +1,8 @@ import django_filters from django.db.models import Q -from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from utilities.filters import TagFilter, TreeNodeMultipleChoiceFilter -from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet +from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from .models import Tenant, TenantGroup @@ -14,7 +13,7 @@ __all__ = ( ) -class TenantGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class TenantGroupFilterSet(OrganizationalModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=TenantGroup.objects.all(), label='Tenant group (ID)', @@ -31,7 +30,7 @@ class TenantGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdate fields = ['id', 'name', 'slug', 'description'] -class TenantFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class TenantFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/utilities/filtersets.py b/netbox/utilities/filtersets.py index 0fb188d11..c3a2e8443 100644 --- a/netbox/utilities/filtersets.py +++ b/netbox/utilities/filtersets.py @@ -1,9 +1,13 @@ import django_filters from copy import deepcopy -from dcim.forms import MACAddressField +from django.contrib.contenttypes.models import ContentType from django.db import models from django_filters.utils import get_model_field, resolve_field +from dcim.forms import MACAddressField +from extras.choices import CustomFieldFilterLogicChoices +from extras.filters import CustomFieldFilter +from extras.models import CustomField from utilities.constants import ( FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP, FILTER_NUMERIC_BASED_LOOKUP_MAP @@ -11,6 +15,14 @@ from utilities.constants import ( from utilities import filters +__all__ = ( + 'BaseFilterSet', + 'ChangeLoggedModelFilterSet', + 'OrganizationalModelFilterSet', + 'PrimaryModelFilterSet', +) + + # # FilterSets # @@ -172,7 +184,43 @@ class BaseFilterSet(django_filters.FilterSet): return filters -class NameSlugSearchFilterSet(django_filters.FilterSet): +class ChangeLoggedModelFilterSet(BaseFilterSet): + created = django_filters.DateFilter() + created__gte = django_filters.DateFilter( + field_name='created', + lookup_expr='gte' + ) + created__lte = django_filters.DateFilter( + field_name='created', + lookup_expr='lte' + ) + last_updated = django_filters.DateTimeFilter() + last_updated__gte = django_filters.DateTimeFilter( + field_name='last_updated', + lookup_expr='gte' + ) + last_updated__lte = django_filters.DateTimeFilter( + field_name='last_updated', + lookup_expr='lte' + ) + + +class PrimaryModelFilterSet(ChangeLoggedModelFilterSet): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Dynamically add a Filter for each CustomField applicable to the parent model + custom_fields = CustomField.objects.filter( + content_types=ContentType.objects.get_for_model(self._meta.model) + ).exclude( + filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED + ) + for cf in custom_fields: + self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(field_name=cf.name, custom_field=cf) + + +class OrganizationalModelFilterSet(PrimaryModelFilterSet): """ A base class for adding the search method to models which only expose the `name` and `slug` fields """ diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filters.py index 9ace5c49e..187061f5e 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filters.py @@ -2,10 +2,10 @@ import django_filters from django.db.models import Q from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup -from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet, LocalConfigContextFilterSet +from extras.filtersets import LocalConfigContextFilterSet from tenancy.filters import TenancyFilterSet from utilities.filters import MultiValueMACAddressFilter, TagFilter, TreeNodeMultipleChoiceFilter -from utilities.filtersets import BaseFilterSet, NameSlugSearchFilterSet +from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface @@ -18,21 +18,21 @@ __all__ = ( ) -class ClusterTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class ClusterTypeFilterSet(OrganizationalModelFilterSet): class Meta: model = ClusterType fields = ['id', 'name', 'slug', 'description'] -class ClusterGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): +class ClusterGroupFilterSet(OrganizationalModelFilterSet): class Meta: model = ClusterGroup fields = ['id', 'name', 'slug', 'description'] -class ClusterFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class ClusterFilterSet(PrimaryModelFilterSet, TenancyFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -108,13 +108,7 @@ class ClusterFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSe ) -class VirtualMachineFilterSet( - BaseFilterSet, - LocalConfigContextFilterSet, - TenancyFilterSet, - CustomFieldModelFilterSet, - CreatedUpdatedFilterSet -): +class VirtualMachineFilterSet(PrimaryModelFilterSet, TenancyFilterSet, LocalConfigContextFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -235,7 +229,7 @@ class VirtualMachineFilterSet( return queryset.exclude(params) -class VMInterfaceFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): +class VMInterfaceFilterSet(PrimaryModelFilterSet): q = django_filters.CharFilter( method='search', label='Search', From d35ac1347cebd46740188f1b294ac50499f3c1ea Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Apr 2021 16:12:31 -0400 Subject: [PATCH 3/5] Move TagFilter to extras --- netbox/circuits/filters.py | 3 ++- netbox/dcim/filters.py | 3 ++- netbox/extras/filters.py | 16 ++++++++++++++++ netbox/ipam/filters.py | 4 ++-- netbox/secrets/filters.py | 2 +- netbox/tenancy/filters.py | 3 ++- netbox/utilities/filters.py | 16 ---------------- netbox/utilities/filtersets.py | 4 ++-- netbox/utilities/tests/test_filters.py | 3 ++- netbox/virtualization/filters.py | 3 ++- 10 files changed, 31 insertions(+), 26 deletions(-) diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index 6ff6bb104..bb778dec7 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filters.py @@ -3,8 +3,9 @@ from django.db.models import Q from dcim.filters import CableTerminationFilterSet from dcim.models import Region, Site, SiteGroup +from extras.filters import TagFilter from tenancy.filters import TenancyFilterSet -from utilities.filters import TagFilter, TreeNodeMultipleChoiceFilter +from utilities.filters import TreeNodeMultipleChoiceFilter from utilities.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * from .models import * diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index a45900466..3c81da460 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -1,12 +1,13 @@ import django_filters from django.contrib.auth.models import User +from extras.filters import TagFilter from extras.filtersets import LocalConfigContextFilterSet from tenancy.filters import TenancyFilterSet from tenancy.models import Tenant from utilities.choices import ColorChoices from utilities.filters import ( - MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, TagFilter, TreeNodeMultipleChoiceFilter, + MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, TreeNodeMultipleChoiceFilter, ) from utilities.filtersets import ( BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet, diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index dff12aa91..3757d73f3 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -1,6 +1,7 @@ import django_filters from django.forms import DateField, IntegerField, NullBooleanField +from .models import Tag from .choices import * __all__ = ( @@ -36,3 +37,18 @@ class CustomFieldFilter(django_filters.Filter): if custom_field.type not in EXACT_FILTER_TYPES: if custom_field.filter_logic == CustomFieldFilterLogicChoices.FILTER_LOOSE: self.lookup_expr = 'icontains' + + +class TagFilter(django_filters.ModelMultipleChoiceFilter): + """ + Match on one or more assigned tags. If multiple tags are specified (e.g. ?tag=foo&tag=bar), the queryset is filtered + to objects matching all tags. + """ + def __init__(self, *args, **kwargs): + + kwargs.setdefault('field_name', 'tags__slug') + kwargs.setdefault('to_field_name', 'slug') + kwargs.setdefault('conjoined', True) + kwargs.setdefault('queryset', Tag.objects.all()) + + super().__init__(*args, **kwargs) diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index 4ecea50af..db1b76f31 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -6,10 +6,10 @@ from django.db.models import Q from netaddr.core import AddrFormatError from dcim.models import Device, Interface, Region, Site, SiteGroup +from extras.filters import TagFilter from tenancy.filters import TenancyFilterSet from utilities.filters import ( - ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TagFilter, - TreeNodeMultipleChoiceFilter, + ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter, ) from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from virtualization.models import VirtualMachine, VMInterface diff --git a/netbox/secrets/filters.py b/netbox/secrets/filters.py index 6571c60f9..1149fbd9b 100644 --- a/netbox/secrets/filters.py +++ b/netbox/secrets/filters.py @@ -2,7 +2,7 @@ import django_filters from django.db.models import Q from dcim.models import Device -from utilities.filters import TagFilter +from extras.filters import TagFilter from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from virtualization.models import VirtualMachine from .models import Secret, SecretRole diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filters.py index 9cbaed170..6a428f4b6 100644 --- a/netbox/tenancy/filters.py +++ b/netbox/tenancy/filters.py @@ -1,7 +1,8 @@ import django_filters from django.db.models import Q -from utilities.filters import TagFilter, TreeNodeMultipleChoiceFilter +from extras.filters import TagFilter +from utilities.filters import TreeNodeMultipleChoiceFilter from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from .models import Tenant, TenantGroup diff --git a/netbox/utilities/filters.py b/netbox/utilities/filters.py index 97608ed22..ed71afc1b 100644 --- a/netbox/utilities/filters.py +++ b/netbox/utilities/filters.py @@ -4,7 +4,6 @@ from django.conf import settings from django_filters.constants import EMPTY_VALUES from dcim.forms import MACAddressField -from extras.models import Tag def multivalue_field_factory(field_class): @@ -84,21 +83,6 @@ class NullableCharFieldFilter(django_filters.CharFilter): return qs.distinct() if self.distinct else qs -class TagFilter(django_filters.ModelMultipleChoiceFilter): - """ - Match on one or more assigned tags. If multiple tags are specified (e.g. ?tag=foo&tag=bar), the queryset is filtered - to objects matching all tags. - """ - def __init__(self, *args, **kwargs): - - kwargs.setdefault('field_name', 'tags__slug') - kwargs.setdefault('to_field_name', 'slug') - kwargs.setdefault('conjoined', True) - kwargs.setdefault('queryset', Tag.objects.all()) - - super().__init__(*args, **kwargs) - - class NumericArrayFilter(django_filters.NumberFilter): """ Filter based on the presence of an integer within an ArrayField. diff --git a/netbox/utilities/filtersets.py b/netbox/utilities/filtersets.py index c3a2e8443..f738441dd 100644 --- a/netbox/utilities/filtersets.py +++ b/netbox/utilities/filtersets.py @@ -6,7 +6,7 @@ from django_filters.utils import get_model_field, resolve_field from dcim.forms import MACAddressField from extras.choices import CustomFieldFilterLogicChoices -from extras.filters import CustomFieldFilter +from extras.filters import CustomFieldFilter, TagFilter from extras.models import CustomField from utilities.constants import ( FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP, @@ -100,7 +100,7 @@ class BaseFilterSet(django_filters.FilterSet): elif isinstance(existing_filter, ( django_filters.ModelChoiceFilter, django_filters.ModelMultipleChoiceFilter, - filters.TagFilter + TagFilter )) or existing_filter.extra.get('choices'): # These filter types support only negation lookup_map = FILTER_NEGATION_LOOKUP_MAP diff --git a/netbox/utilities/tests/test_filters.py b/netbox/utilities/tests/test_filters.py index 6d2826b70..21f020fb4 100644 --- a/netbox/utilities/tests/test_filters.py +++ b/netbox/utilities/tests/test_filters.py @@ -11,10 +11,11 @@ from dcim.filters import DeviceFilterSet, SiteFilterSet from dcim.models import ( Device, DeviceRole, DeviceType, Interface, Manufacturer, Platform, Rack, Region, Site ) +from extras.filters import TagFilter from extras.models import TaggedItem from utilities.filters import ( MACAddressFilter, MultiValueCharFilter, MultiValueDateFilter, MultiValueDateTimeFilter, MultiValueNumberFilter, - MultiValueTimeFilter, TagFilter, TreeNodeMultipleChoiceFilter, + MultiValueTimeFilter, TreeNodeMultipleChoiceFilter, ) from utilities.filtersets import BaseFilterSet diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filters.py index 187061f5e..6c2e0a48a 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filters.py @@ -2,9 +2,10 @@ import django_filters from django.db.models import Q from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup +from extras.filters import TagFilter from extras.filtersets import LocalConfigContextFilterSet from tenancy.filters import TenancyFilterSet -from utilities.filters import MultiValueMACAddressFilter, TagFilter, TreeNodeMultipleChoiceFilter +from utilities.filters import MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface From 1024782b9e0abb48f6da65f8248741227d53dbed Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Apr 2021 16:38:56 -0400 Subject: [PATCH 4/5] Rename FilterSet modules --- netbox/circuits/api/views.py | 12 +- netbox/circuits/{filters.py => filtersets.py} | 4 +- netbox/circuits/tests/test_filters.py | 2 +- netbox/circuits/views.py | 22 +-- netbox/dcim/api/views.py | 74 ++++---- netbox/dcim/{filters.py => filtersets.py} | 2 +- netbox/dcim/tests/test_filters.py | 2 +- netbox/dcim/views.py | 160 +++++++++--------- netbox/extras/filters.py | 1 + netbox/extras/tests/test_customfields.py | 2 +- netbox/ipam/api/views.py | 22 +-- netbox/ipam/{filters.py => filtersets.py} | 2 +- netbox/ipam/tests/test_filters.py | 2 +- netbox/ipam/views.py | 60 +++---- netbox/netbox/constants.py | 12 +- netbox/secrets/api/views.py | 6 +- netbox/secrets/{filters.py => filtersets.py} | 0 netbox/secrets/tests/test_filters.py | 2 +- netbox/secrets/views.py | 12 +- netbox/tenancy/api/views.py | 6 +- netbox/tenancy/{filters.py => filtersets.py} | 0 netbox/tenancy/tests/test_filters.py | 2 +- netbox/tenancy/views.py | 10 +- netbox/users/api/views.py | 8 +- netbox/users/{filters.py => filtersets.py} | 0 netbox/users/tests/test_filters.py | 2 +- netbox/utilities/tests/test_filters.py | 2 +- netbox/virtualization/api/views.py | 12 +- .../{filters.py => filtersets.py} | 2 +- netbox/virtualization/tests/test_filters.py | 2 +- netbox/virtualization/views.py | 22 +-- 31 files changed, 234 insertions(+), 233 deletions(-) rename netbox/circuits/{filters.py => filtersets.py} (98%) rename netbox/dcim/{filters.py => filtersets.py} (99%) rename netbox/ipam/{filters.py => filtersets.py} (99%) rename netbox/secrets/{filters.py => filtersets.py} (100%) rename netbox/tenancy/{filters.py => filtersets.py} (100%) rename netbox/users/{filters.py => filtersets.py} (100%) rename netbox/virtualization/{filters.py => filtersets.py} (99%) diff --git a/netbox/circuits/api/views.py b/netbox/circuits/api/views.py index 0ea8d1973..3bceb2de0 100644 --- a/netbox/circuits/api/views.py +++ b/netbox/circuits/api/views.py @@ -1,6 +1,6 @@ from rest_framework.routers import APIRootView -from circuits import filters +from circuits import filtersets from circuits.models import * from dcim.api.views import PassThroughPortMixin from extras.api.views import CustomFieldModelViewSet @@ -26,7 +26,7 @@ class ProviderViewSet(CustomFieldModelViewSet): circuit_count=count_related(Circuit, 'provider') ) serializer_class = serializers.ProviderSerializer - filterset_class = filters.ProviderFilterSet + filterset_class = filtersets.ProviderFilterSet # @@ -38,7 +38,7 @@ class CircuitTypeViewSet(CustomFieldModelViewSet): circuit_count=count_related(Circuit, 'type') ) serializer_class = serializers.CircuitTypeSerializer - filterset_class = filters.CircuitTypeFilterSet + filterset_class = filtersets.CircuitTypeFilterSet # @@ -50,7 +50,7 @@ class CircuitViewSet(CustomFieldModelViewSet): 'type', 'tenant', 'provider', 'termination_a', 'termination_z' ).prefetch_related('tags') serializer_class = serializers.CircuitSerializer - filterset_class = filters.CircuitFilterSet + filterset_class = filtersets.CircuitFilterSet # @@ -62,7 +62,7 @@ class CircuitTerminationViewSet(PassThroughPortMixin, ModelViewSet): 'circuit', 'site', 'provider_network', 'cable' ) serializer_class = serializers.CircuitTerminationSerializer - filterset_class = filters.CircuitTerminationFilterSet + filterset_class = filtersets.CircuitTerminationFilterSet brief_prefetch_fields = ['circuit'] @@ -73,4 +73,4 @@ class CircuitTerminationViewSet(PassThroughPortMixin, ModelViewSet): class ProviderNetworkViewSet(CustomFieldModelViewSet): queryset = ProviderNetwork.objects.prefetch_related('tags') serializer_class = serializers.ProviderNetworkSerializer - filterset_class = filters.ProviderNetworkFilterSet + filterset_class = filtersets.ProviderNetworkFilterSet diff --git a/netbox/circuits/filters.py b/netbox/circuits/filtersets.py similarity index 98% rename from netbox/circuits/filters.py rename to netbox/circuits/filtersets.py index bb778dec7..cd0b720e6 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filtersets.py @@ -1,10 +1,10 @@ import django_filters from django.db.models import Q -from dcim.filters import CableTerminationFilterSet +from dcim.filtersets import CableTerminationFilterSet from dcim.models import Region, Site, SiteGroup from extras.filters import TagFilter -from tenancy.filters import TenancyFilterSet +from tenancy.filtersets import TenancyFilterSet from utilities.filters import TreeNodeMultipleChoiceFilter from utilities.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * diff --git a/netbox/circuits/tests/test_filters.py b/netbox/circuits/tests/test_filters.py index 448e42368..40c68c73c 100644 --- a/netbox/circuits/tests/test_filters.py +++ b/netbox/circuits/tests/test_filters.py @@ -1,7 +1,7 @@ from django.test import TestCase from circuits.choices import * -from circuits.filters import * +from circuits.filtersets import * from circuits.models import * from dcim.models import Cable, Region, Site, SiteGroup from tenancy.models import Tenant, TenantGroup diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 92e53c30f..6fd0c2208 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -7,7 +7,7 @@ from netbox.views import generic from utilities.forms import ConfirmationForm from utilities.tables import paginate_table from utilities.utils import count_related -from . import filters, forms, tables +from . import filtersets, forms, tables from .choices import CircuitTerminationSideChoices from .models import * @@ -20,7 +20,7 @@ class ProviderListView(generic.ObjectListView): queryset = Provider.objects.annotate( count_circuits=count_related(Circuit, 'provider') ) - filterset = filters.ProviderFilterSet + filterset = filtersets.ProviderFilterSet filterset_form = forms.ProviderFilterForm table = tables.ProviderTable @@ -63,7 +63,7 @@ class ProviderBulkEditView(generic.BulkEditView): queryset = Provider.objects.annotate( count_circuits=count_related(Circuit, 'provider') ) - filterset = filters.ProviderFilterSet + filterset = filtersets.ProviderFilterSet table = tables.ProviderTable form = forms.ProviderBulkEditForm @@ -72,7 +72,7 @@ class ProviderBulkDeleteView(generic.BulkDeleteView): queryset = Provider.objects.annotate( count_circuits=count_related(Circuit, 'provider') ) - filterset = filters.ProviderFilterSet + filterset = filtersets.ProviderFilterSet table = tables.ProviderTable @@ -82,7 +82,7 @@ class ProviderBulkDeleteView(generic.BulkDeleteView): class ProviderNetworkListView(generic.ObjectListView): queryset = ProviderNetwork.objects.all() - filterset = filters.ProviderNetworkFilterSet + filterset = filtersets.ProviderNetworkFilterSet filterset_form = forms.ProviderNetworkFilterForm table = tables.ProviderNetworkTable @@ -125,14 +125,14 @@ class ProviderNetworkBulkImportView(generic.BulkImportView): class ProviderNetworkBulkEditView(generic.BulkEditView): queryset = ProviderNetwork.objects.all() - filterset = filters.ProviderNetworkFilterSet + filterset = filtersets.ProviderNetworkFilterSet table = tables.ProviderNetworkTable form = forms.ProviderNetworkBulkEditForm class ProviderNetworkBulkDeleteView(generic.BulkDeleteView): queryset = ProviderNetwork.objects.all() - filterset = filters.ProviderNetworkFilterSet + filterset = filtersets.ProviderNetworkFilterSet table = tables.ProviderNetworkTable @@ -183,7 +183,7 @@ class CircuitTypeBulkEditView(generic.BulkEditView): queryset = CircuitType.objects.annotate( circuit_count=count_related(Circuit, 'type') ) - filterset = filters.CircuitTypeFilterSet + filterset = filtersets.CircuitTypeFilterSet table = tables.CircuitTypeTable form = forms.CircuitTypeBulkEditForm @@ -203,7 +203,7 @@ class CircuitListView(generic.ObjectListView): queryset = Circuit.objects.prefetch_related( 'provider', 'type', 'tenant', 'termination_a', 'termination_z' ) - filterset = filters.CircuitFilterSet + filterset = filtersets.CircuitFilterSet filterset_form = forms.CircuitFilterForm table = tables.CircuitTable @@ -252,7 +252,7 @@ class CircuitBulkEditView(generic.BulkEditView): queryset = Circuit.objects.prefetch_related( 'provider', 'type', 'tenant', 'terminations' ) - filterset = filters.CircuitFilterSet + filterset = filtersets.CircuitFilterSet table = tables.CircuitTable form = forms.CircuitBulkEditForm @@ -261,7 +261,7 @@ class CircuitBulkDeleteView(generic.BulkDeleteView): queryset = Circuit.objects.prefetch_related( 'provider', 'type', 'tenant', 'terminations' ) - filterset = filters.CircuitFilterSet + filterset = filtersets.CircuitFilterSet table = tables.CircuitTable diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index cb46c1eca..9d402227f 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -16,7 +16,7 @@ from rest_framework.routers import APIRootView from rest_framework.viewsets import GenericViewSet, ViewSet from circuits.models import Circuit -from dcim import filters +from dcim import filtersets from dcim.models import * from extras.api.views import ConfigContextQuerySetMixin, CustomFieldModelViewSet from ipam.models import Prefix, VLAN @@ -103,7 +103,7 @@ class RegionViewSet(CustomFieldModelViewSet): cumulative=True ) serializer_class = serializers.RegionSerializer - filterset_class = filters.RegionFilterSet + filterset_class = filtersets.RegionFilterSet # @@ -119,7 +119,7 @@ class SiteGroupViewSet(CustomFieldModelViewSet): cumulative=True ) serializer_class = serializers.SiteGroupSerializer - filterset_class = filters.SiteGroupFilterSet + filterset_class = filtersets.SiteGroupFilterSet # @@ -138,7 +138,7 @@ class SiteViewSet(CustomFieldModelViewSet): virtualmachine_count=count_related(VirtualMachine, 'cluster__site') ) serializer_class = serializers.SiteSerializer - filterset_class = filters.SiteFilterSet + filterset_class = filtersets.SiteFilterSet # @@ -160,7 +160,7 @@ class LocationViewSet(CustomFieldModelViewSet): cumulative=True ).prefetch_related('site') serializer_class = serializers.LocationSerializer - filterset_class = filters.LocationFilterSet + filterset_class = filtersets.LocationFilterSet # @@ -172,7 +172,7 @@ class RackRoleViewSet(CustomFieldModelViewSet): rack_count=count_related(Rack, 'role') ) serializer_class = serializers.RackRoleSerializer - filterset_class = filters.RackRoleFilterSet + filterset_class = filtersets.RackRoleFilterSet # @@ -187,7 +187,7 @@ class RackViewSet(CustomFieldModelViewSet): powerfeed_count=count_related(PowerFeed, 'rack') ) serializer_class = serializers.RackSerializer - filterset_class = filters.RackFilterSet + filterset_class = filtersets.RackFilterSet @swagger_auto_schema( responses={200: serializers.RackUnitSerializer(many=True)}, @@ -244,7 +244,7 @@ class RackViewSet(CustomFieldModelViewSet): class RackReservationViewSet(ModelViewSet): queryset = RackReservation.objects.prefetch_related('rack', 'user', 'tenant') serializer_class = serializers.RackReservationSerializer - filterset_class = filters.RackReservationFilterSet + filterset_class = filtersets.RackReservationFilterSet # Assign user from request def perform_create(self, serializer): @@ -262,7 +262,7 @@ class ManufacturerViewSet(CustomFieldModelViewSet): platform_count=count_related(Platform, 'manufacturer') ) serializer_class = serializers.ManufacturerSerializer - filterset_class = filters.ManufacturerFilterSet + filterset_class = filtersets.ManufacturerFilterSet # @@ -274,7 +274,7 @@ class DeviceTypeViewSet(CustomFieldModelViewSet): device_count=count_related(Device, 'device_type') ) serializer_class = serializers.DeviceTypeSerializer - filterset_class = filters.DeviceTypeFilterSet + filterset_class = filtersets.DeviceTypeFilterSet brief_prefetch_fields = ['manufacturer'] @@ -285,49 +285,49 @@ class DeviceTypeViewSet(CustomFieldModelViewSet): class ConsolePortTemplateViewSet(ModelViewSet): queryset = ConsolePortTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.ConsolePortTemplateSerializer - filterset_class = filters.ConsolePortTemplateFilterSet + filterset_class = filtersets.ConsolePortTemplateFilterSet class ConsoleServerPortTemplateViewSet(ModelViewSet): queryset = ConsoleServerPortTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.ConsoleServerPortTemplateSerializer - filterset_class = filters.ConsoleServerPortTemplateFilterSet + filterset_class = filtersets.ConsoleServerPortTemplateFilterSet class PowerPortTemplateViewSet(ModelViewSet): queryset = PowerPortTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.PowerPortTemplateSerializer - filterset_class = filters.PowerPortTemplateFilterSet + filterset_class = filtersets.PowerPortTemplateFilterSet class PowerOutletTemplateViewSet(ModelViewSet): queryset = PowerOutletTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.PowerOutletTemplateSerializer - filterset_class = filters.PowerOutletTemplateFilterSet + filterset_class = filtersets.PowerOutletTemplateFilterSet class InterfaceTemplateViewSet(ModelViewSet): queryset = InterfaceTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.InterfaceTemplateSerializer - filterset_class = filters.InterfaceTemplateFilterSet + filterset_class = filtersets.InterfaceTemplateFilterSet class FrontPortTemplateViewSet(ModelViewSet): queryset = FrontPortTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.FrontPortTemplateSerializer - filterset_class = filters.FrontPortTemplateFilterSet + filterset_class = filtersets.FrontPortTemplateFilterSet class RearPortTemplateViewSet(ModelViewSet): queryset = RearPortTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.RearPortTemplateSerializer - filterset_class = filters.RearPortTemplateFilterSet + filterset_class = filtersets.RearPortTemplateFilterSet class DeviceBayTemplateViewSet(ModelViewSet): queryset = DeviceBayTemplate.objects.prefetch_related('device_type__manufacturer') serializer_class = serializers.DeviceBayTemplateSerializer - filterset_class = filters.DeviceBayTemplateFilterSet + filterset_class = filtersets.DeviceBayTemplateFilterSet # @@ -340,7 +340,7 @@ class DeviceRoleViewSet(CustomFieldModelViewSet): virtualmachine_count=count_related(VirtualMachine, 'role') ) serializer_class = serializers.DeviceRoleSerializer - filterset_class = filters.DeviceRoleFilterSet + filterset_class = filtersets.DeviceRoleFilterSet # @@ -353,7 +353,7 @@ class PlatformViewSet(CustomFieldModelViewSet): virtualmachine_count=count_related(VirtualMachine, 'platform') ) serializer_class = serializers.PlatformSerializer - filterset_class = filters.PlatformFilterSet + filterset_class = filtersets.PlatformFilterSet # @@ -365,7 +365,7 @@ class DeviceViewSet(ConfigContextQuerySetMixin, CustomFieldModelViewSet): 'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'site', 'location', 'rack', 'parent_bay', 'virtual_chassis__master', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'tags', ) - filterset_class = filters.DeviceFilterSet + filterset_class = filtersets.DeviceFilterSet def get_serializer_class(self): """ @@ -510,7 +510,7 @@ class DeviceViewSet(ConfigContextQuerySetMixin, CustomFieldModelViewSet): class ConsolePortViewSet(PathEndpointMixin, ModelViewSet): queryset = ConsolePort.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags') serializer_class = serializers.ConsolePortSerializer - filterset_class = filters.ConsolePortFilterSet + filterset_class = filtersets.ConsolePortFilterSet brief_prefetch_fields = ['device'] @@ -519,21 +519,21 @@ class ConsoleServerPortViewSet(PathEndpointMixin, ModelViewSet): 'device', '_path__destination', 'cable', '_cable_peer', 'tags' ) serializer_class = serializers.ConsoleServerPortSerializer - filterset_class = filters.ConsoleServerPortFilterSet + filterset_class = filtersets.ConsoleServerPortFilterSet brief_prefetch_fields = ['device'] class PowerPortViewSet(PathEndpointMixin, ModelViewSet): queryset = PowerPort.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags') serializer_class = serializers.PowerPortSerializer - filterset_class = filters.PowerPortFilterSet + filterset_class = filtersets.PowerPortFilterSet brief_prefetch_fields = ['device'] class PowerOutletViewSet(PathEndpointMixin, ModelViewSet): queryset = PowerOutlet.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags') serializer_class = serializers.PowerOutletSerializer - filterset_class = filters.PowerOutletFilterSet + filterset_class = filtersets.PowerOutletFilterSet brief_prefetch_fields = ['device'] @@ -542,35 +542,35 @@ class InterfaceViewSet(PathEndpointMixin, ModelViewSet): 'device', 'parent', 'lag', '_path__destination', 'cable', '_cable_peer', 'ip_addresses', 'tags' ) serializer_class = serializers.InterfaceSerializer - filterset_class = filters.InterfaceFilterSet + filterset_class = filtersets.InterfaceFilterSet brief_prefetch_fields = ['device'] class FrontPortViewSet(PassThroughPortMixin, ModelViewSet): queryset = FrontPort.objects.prefetch_related('device__device_type__manufacturer', 'rear_port', 'cable', 'tags') serializer_class = serializers.FrontPortSerializer - filterset_class = filters.FrontPortFilterSet + filterset_class = filtersets.FrontPortFilterSet brief_prefetch_fields = ['device'] class RearPortViewSet(PassThroughPortMixin, ModelViewSet): queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags') serializer_class = serializers.RearPortSerializer - filterset_class = filters.RearPortFilterSet + filterset_class = filtersets.RearPortFilterSet brief_prefetch_fields = ['device'] class DeviceBayViewSet(ModelViewSet): queryset = DeviceBay.objects.prefetch_related('installed_device').prefetch_related('tags') serializer_class = serializers.DeviceBaySerializer - filterset_class = filters.DeviceBayFilterSet + filterset_class = filtersets.DeviceBayFilterSet brief_prefetch_fields = ['device'] class InventoryItemViewSet(ModelViewSet): queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer').prefetch_related('tags') serializer_class = serializers.InventoryItemSerializer - filterset_class = filters.InventoryItemFilterSet + filterset_class = filtersets.InventoryItemFilterSet brief_prefetch_fields = ['device'] @@ -583,7 +583,7 @@ class ConsoleConnectionViewSet(ListModelMixin, GenericViewSet): _path__destination_id__isnull=False ) serializer_class = serializers.ConsolePortSerializer - filterset_class = filters.ConsoleConnectionFilterSet + filterset_class = filtersets.ConsoleConnectionFilterSet class PowerConnectionViewSet(ListModelMixin, GenericViewSet): @@ -591,7 +591,7 @@ class PowerConnectionViewSet(ListModelMixin, GenericViewSet): _path__destination_id__isnull=False ) serializer_class = serializers.PowerPortSerializer - filterset_class = filters.PowerConnectionFilterSet + filterset_class = filtersets.PowerConnectionFilterSet class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet): @@ -603,7 +603,7 @@ class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet): pk__lt=F('_path__destination_id') ) serializer_class = serializers.InterfaceConnectionSerializer - filterset_class = filters.InterfaceConnectionFilterSet + filterset_class = filtersets.InterfaceConnectionFilterSet # @@ -616,7 +616,7 @@ class CableViewSet(ModelViewSet): 'termination_a', 'termination_b' ) serializer_class = serializers.CableSerializer - filterset_class = filters.CableFilterSet + filterset_class = filtersets.CableFilterSet # @@ -628,7 +628,7 @@ class VirtualChassisViewSet(ModelViewSet): member_count=count_related(Device, 'virtual_chassis') ) serializer_class = serializers.VirtualChassisSerializer - filterset_class = filters.VirtualChassisFilterSet + filterset_class = filtersets.VirtualChassisFilterSet brief_prefetch_fields = ['master'] @@ -643,7 +643,7 @@ class PowerPanelViewSet(ModelViewSet): powerfeed_count=count_related(PowerFeed, 'power_panel') ) serializer_class = serializers.PowerPanelSerializer - filterset_class = filters.PowerPanelFilterSet + filterset_class = filtersets.PowerPanelFilterSet # @@ -655,7 +655,7 @@ class PowerFeedViewSet(PathEndpointMixin, CustomFieldModelViewSet): 'power_panel', 'rack', '_path__destination', 'cable', '_cable_peer', 'tags' ) serializer_class = serializers.PowerFeedSerializer - filterset_class = filters.PowerFeedFilterSet + filterset_class = filtersets.PowerFeedFilterSet # diff --git a/netbox/dcim/filters.py b/netbox/dcim/filtersets.py similarity index 99% rename from netbox/dcim/filters.py rename to netbox/dcim/filtersets.py index 3c81da460..62f59c352 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filtersets.py @@ -3,7 +3,7 @@ from django.contrib.auth.models import User from extras.filters import TagFilter from extras.filtersets import LocalConfigContextFilterSet -from tenancy.filters import TenancyFilterSet +from tenancy.filtersets import TenancyFilterSet from tenancy.models import Tenant from utilities.choices import ColorChoices from utilities.filters import ( diff --git a/netbox/dcim/tests/test_filters.py b/netbox/dcim/tests/test_filters.py index 632a10c46..5e7b84463 100644 --- a/netbox/dcim/tests/test_filters.py +++ b/netbox/dcim/tests/test_filters.py @@ -2,7 +2,7 @@ from django.contrib.auth.models import User from django.test import TestCase from dcim.choices import * -from dcim.filters import * +from dcim.filtersets import * from dcim.models import * from ipam.models import IPAddress from tenancy.models import Tenant, TenantGroup diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 69e043425..72438fc9a 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -24,7 +24,7 @@ from utilities.tables import paginate_table from utilities.utils import csv_format, count_related from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin from virtualization.models import VirtualMachine -from . import filters, forms, tables +from . import filtersets, forms, tables from .choices import DeviceFaceChoices from .constants import NONCONNECTABLE_IFACE_TYPES from .models import ( @@ -107,7 +107,7 @@ class RegionListView(generic.ObjectListView): 'site_count', cumulative=True ) - filterset = filters.RegionFilterSet + filterset = filtersets.RegionFilterSet filterset_form = forms.RegionFilterForm table = tables.RegionTable @@ -163,7 +163,7 @@ class RegionBulkEditView(generic.BulkEditView): 'site_count', cumulative=True ) - filterset = filters.RegionFilterSet + filterset = filtersets.RegionFilterSet table = tables.RegionTable form = forms.RegionBulkEditForm @@ -176,7 +176,7 @@ class RegionBulkDeleteView(generic.BulkDeleteView): 'site_count', cumulative=True ) - filterset = filters.RegionFilterSet + filterset = filtersets.RegionFilterSet table = tables.RegionTable @@ -192,7 +192,7 @@ class SiteGroupListView(generic.ObjectListView): 'site_count', cumulative=True ) - filterset = filters.SiteGroupFilterSet + filterset = filtersets.SiteGroupFilterSet filterset_form = forms.SiteGroupFilterForm table = tables.SiteGroupTable @@ -248,7 +248,7 @@ class SiteGroupBulkEditView(generic.BulkEditView): 'site_count', cumulative=True ) - filterset = filters.SiteGroupFilterSet + filterset = filtersets.SiteGroupFilterSet table = tables.SiteGroupTable form = forms.SiteGroupBulkEditForm @@ -261,7 +261,7 @@ class SiteGroupBulkDeleteView(generic.BulkDeleteView): 'site_count', cumulative=True ) - filterset = filters.SiteGroupFilterSet + filterset = filtersets.SiteGroupFilterSet table = tables.SiteGroupTable @@ -271,7 +271,7 @@ class SiteGroupBulkDeleteView(generic.BulkDeleteView): class SiteListView(generic.ObjectListView): queryset = Site.objects.all() - filterset = filters.SiteFilterSet + filterset = filtersets.SiteFilterSet filterset_form = forms.SiteFilterForm table = tables.SiteTable @@ -326,14 +326,14 @@ class SiteBulkImportView(generic.BulkImportView): class SiteBulkEditView(generic.BulkEditView): queryset = Site.objects.prefetch_related('region', 'tenant') - filterset = filters.SiteFilterSet + filterset = filtersets.SiteFilterSet table = tables.SiteTable form = forms.SiteBulkEditForm class SiteBulkDeleteView(generic.BulkDeleteView): queryset = Site.objects.prefetch_related('region', 'tenant') - filterset = filters.SiteFilterSet + filterset = filtersets.SiteFilterSet table = tables.SiteTable @@ -355,7 +355,7 @@ class LocationListView(generic.ObjectListView): 'rack_count', cumulative=True ) - filterset = filters.LocationFilterSet + filterset = filtersets.LocationFilterSet filterset_form = forms.LocationFilterForm table = tables.LocationTable @@ -414,7 +414,7 @@ class LocationBulkEditView(generic.BulkEditView): 'rack_count', cumulative=True ).prefetch_related('site') - filterset = filters.LocationFilterSet + filterset = filtersets.LocationFilterSet table = tables.LocationTable form = forms.LocationBulkEditForm @@ -427,7 +427,7 @@ class LocationBulkDeleteView(generic.BulkDeleteView): 'rack_count', cumulative=True ).prefetch_related('site') - filterset = filters.LocationFilterSet + filterset = filtersets.LocationFilterSet table = tables.LocationTable @@ -478,7 +478,7 @@ class RackRoleBulkEditView(generic.BulkEditView): queryset = RackRole.objects.annotate( rack_count=count_related(Rack, 'role') ) - filterset = filters.RackRoleFilterSet + filterset = filtersets.RackRoleFilterSet table = tables.RackRoleTable form = forms.RackRoleBulkEditForm @@ -500,7 +500,7 @@ class RackListView(generic.ObjectListView): ).annotate( device_count=count_related(Device, 'rack') ) - filterset = filters.RackFilterSet + filterset = filtersets.RackFilterSet filterset_form = forms.RackFilterForm table = tables.RackDetailTable @@ -513,7 +513,7 @@ class RackElevationListView(generic.ObjectListView): def get(self, request): - racks = filters.RackFilterSet(request.GET, self.queryset).qs + racks = filtersets.RackFilterSet(request.GET, self.queryset).qs total_count = racks.count() # Determine ordering @@ -602,14 +602,14 @@ class RackBulkImportView(generic.BulkImportView): class RackBulkEditView(generic.BulkEditView): queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role') - filterset = filters.RackFilterSet + filterset = filtersets.RackFilterSet table = tables.RackTable form = forms.RackBulkEditForm class RackBulkDeleteView(generic.BulkDeleteView): queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role') - filterset = filters.RackFilterSet + filterset = filtersets.RackFilterSet table = tables.RackTable @@ -619,7 +619,7 @@ class RackBulkDeleteView(generic.BulkDeleteView): class RackReservationListView(generic.ObjectListView): queryset = RackReservation.objects.all() - filterset = filters.RackReservationFilterSet + filterset = filtersets.RackReservationFilterSet filterset_form = forms.RackReservationFilterForm table = tables.RackReservationTable @@ -662,14 +662,14 @@ class RackReservationImportView(generic.BulkImportView): class RackReservationBulkEditView(generic.BulkEditView): queryset = RackReservation.objects.prefetch_related('rack', 'user') - filterset = filters.RackReservationFilterSet + filterset = filtersets.RackReservationFilterSet table = tables.RackReservationTable form = forms.RackReservationBulkEditForm class RackReservationBulkDeleteView(generic.BulkDeleteView): queryset = RackReservation.objects.prefetch_related('rack', 'user') - filterset = filters.RackReservationFilterSet + filterset = filtersets.RackReservationFilterSet table = tables.RackReservationTable @@ -722,7 +722,7 @@ class ManufacturerBulkEditView(generic.BulkEditView): queryset = Manufacturer.objects.annotate( devicetype_count=count_related(DeviceType, 'manufacturer') ) - filterset = filters.ManufacturerFilterSet + filterset = filtersets.ManufacturerFilterSet table = tables.ManufacturerTable form = forms.ManufacturerBulkEditForm @@ -742,7 +742,7 @@ class DeviceTypeListView(generic.ObjectListView): queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( instance_count=count_related(Device, 'device_type') ) - filterset = filters.DeviceTypeFilterSet + filterset = filtersets.DeviceTypeFilterSet filterset_form = forms.DeviceTypeFilterForm table = tables.DeviceTypeTable @@ -848,7 +848,7 @@ class DeviceTypeBulkEditView(generic.BulkEditView): queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( instance_count=count_related(Device, 'device_type') ) - filterset = filters.DeviceTypeFilterSet + filterset = filtersets.DeviceTypeFilterSet table = tables.DeviceTypeTable form = forms.DeviceTypeBulkEditForm @@ -857,7 +857,7 @@ class DeviceTypeBulkDeleteView(generic.BulkDeleteView): queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( instance_count=count_related(Device, 'device_type') ) - filterset = filters.DeviceTypeFilterSet + filterset = filtersets.DeviceTypeFilterSet table = tables.DeviceTypeTable @@ -1190,7 +1190,7 @@ class DeviceRoleBulkEditView(generic.BulkEditView): device_count=count_related(Device, 'device_role'), vm_count=count_related(VirtualMachine, 'role') ) - filterset = filters.DeviceRoleFilterSet + filterset = filtersets.DeviceRoleFilterSet table = tables.DeviceRoleTable form = forms.DeviceRoleBulkEditForm @@ -1249,7 +1249,7 @@ class PlatformBulkImportView(generic.BulkImportView): class PlatformBulkEditView(generic.BulkEditView): queryset = Platform.objects.all() - filterset = filters.PlatformFilterSet + filterset = filtersets.PlatformFilterSet table = tables.PlatformTable form = forms.PlatformBulkEditForm @@ -1265,7 +1265,7 @@ class PlatformBulkDeleteView(generic.BulkDeleteView): class DeviceListView(generic.ObjectListView): queryset = Device.objects.all() - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet filterset_form = forms.DeviceFilterForm table = tables.DeviceTable template_name = 'dcim/device_list.html' @@ -1600,14 +1600,14 @@ class ChildDeviceBulkImportView(generic.BulkImportView): class DeviceBulkEditView(generic.BulkEditView): queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer') - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable form = forms.DeviceBulkEditForm class DeviceBulkDeleteView(generic.BulkDeleteView): queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer') - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable @@ -1617,7 +1617,7 @@ class DeviceBulkDeleteView(generic.BulkDeleteView): class ConsolePortListView(generic.ObjectListView): queryset = ConsolePort.objects.all() - filterset = filters.ConsolePortFilterSet + filterset = filtersets.ConsolePortFilterSet filterset_form = forms.ConsolePortFilterForm table = tables.ConsolePortTable action_buttons = ('import', 'export') @@ -1652,7 +1652,7 @@ class ConsolePortBulkImportView(generic.BulkImportView): class ConsolePortBulkEditView(generic.BulkEditView): queryset = ConsolePort.objects.all() - filterset = filters.ConsolePortFilterSet + filterset = filtersets.ConsolePortFilterSet table = tables.ConsolePortTable form = forms.ConsolePortBulkEditForm @@ -1667,7 +1667,7 @@ class ConsolePortBulkDisconnectView(BulkDisconnectView): class ConsolePortBulkDeleteView(generic.BulkDeleteView): queryset = ConsolePort.objects.all() - filterset = filters.ConsolePortFilterSet + filterset = filtersets.ConsolePortFilterSet table = tables.ConsolePortTable @@ -1677,7 +1677,7 @@ class ConsolePortBulkDeleteView(generic.BulkDeleteView): class ConsoleServerPortListView(generic.ObjectListView): queryset = ConsoleServerPort.objects.all() - filterset = filters.ConsoleServerPortFilterSet + filterset = filtersets.ConsoleServerPortFilterSet filterset_form = forms.ConsoleServerPortFilterForm table = tables.ConsoleServerPortTable action_buttons = ('import', 'export') @@ -1712,7 +1712,7 @@ class ConsoleServerPortBulkImportView(generic.BulkImportView): class ConsoleServerPortBulkEditView(generic.BulkEditView): queryset = ConsoleServerPort.objects.all() - filterset = filters.ConsoleServerPortFilterSet + filterset = filtersets.ConsoleServerPortFilterSet table = tables.ConsoleServerPortTable form = forms.ConsoleServerPortBulkEditForm @@ -1727,7 +1727,7 @@ class ConsoleServerPortBulkDisconnectView(BulkDisconnectView): class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView): queryset = ConsoleServerPort.objects.all() - filterset = filters.ConsoleServerPortFilterSet + filterset = filtersets.ConsoleServerPortFilterSet table = tables.ConsoleServerPortTable @@ -1737,7 +1737,7 @@ class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView): class PowerPortListView(generic.ObjectListView): queryset = PowerPort.objects.all() - filterset = filters.PowerPortFilterSet + filterset = filtersets.PowerPortFilterSet filterset_form = forms.PowerPortFilterForm table = tables.PowerPortTable action_buttons = ('import', 'export') @@ -1772,7 +1772,7 @@ class PowerPortBulkImportView(generic.BulkImportView): class PowerPortBulkEditView(generic.BulkEditView): queryset = PowerPort.objects.all() - filterset = filters.PowerPortFilterSet + filterset = filtersets.PowerPortFilterSet table = tables.PowerPortTable form = forms.PowerPortBulkEditForm @@ -1787,7 +1787,7 @@ class PowerPortBulkDisconnectView(BulkDisconnectView): class PowerPortBulkDeleteView(generic.BulkDeleteView): queryset = PowerPort.objects.all() - filterset = filters.PowerPortFilterSet + filterset = filtersets.PowerPortFilterSet table = tables.PowerPortTable @@ -1797,7 +1797,7 @@ class PowerPortBulkDeleteView(generic.BulkDeleteView): class PowerOutletListView(generic.ObjectListView): queryset = PowerOutlet.objects.all() - filterset = filters.PowerOutletFilterSet + filterset = filtersets.PowerOutletFilterSet filterset_form = forms.PowerOutletFilterForm table = tables.PowerOutletTable action_buttons = ('import', 'export') @@ -1832,7 +1832,7 @@ class PowerOutletBulkImportView(generic.BulkImportView): class PowerOutletBulkEditView(generic.BulkEditView): queryset = PowerOutlet.objects.all() - filterset = filters.PowerOutletFilterSet + filterset = filtersets.PowerOutletFilterSet table = tables.PowerOutletTable form = forms.PowerOutletBulkEditForm @@ -1847,7 +1847,7 @@ class PowerOutletBulkDisconnectView(BulkDisconnectView): class PowerOutletBulkDeleteView(generic.BulkDeleteView): queryset = PowerOutlet.objects.all() - filterset = filters.PowerOutletFilterSet + filterset = filtersets.PowerOutletFilterSet table = tables.PowerOutletTable @@ -1857,7 +1857,7 @@ class PowerOutletBulkDeleteView(generic.BulkDeleteView): class InterfaceListView(generic.ObjectListView): queryset = Interface.objects.all() - filterset = filters.InterfaceFilterSet + filterset = filtersets.InterfaceFilterSet filterset_form = forms.InterfaceFilterForm table = tables.InterfaceTable action_buttons = ('import', 'export') @@ -1927,7 +1927,7 @@ class InterfaceBulkImportView(generic.BulkImportView): class InterfaceBulkEditView(generic.BulkEditView): queryset = Interface.objects.all() - filterset = filters.InterfaceFilterSet + filterset = filtersets.InterfaceFilterSet table = tables.InterfaceTable form = forms.InterfaceBulkEditForm @@ -1942,7 +1942,7 @@ class InterfaceBulkDisconnectView(BulkDisconnectView): class InterfaceBulkDeleteView(generic.BulkDeleteView): queryset = Interface.objects.all() - filterset = filters.InterfaceFilterSet + filterset = filtersets.InterfaceFilterSet table = tables.InterfaceTable @@ -1952,7 +1952,7 @@ class InterfaceBulkDeleteView(generic.BulkDeleteView): class FrontPortListView(generic.ObjectListView): queryset = FrontPort.objects.all() - filterset = filters.FrontPortFilterSet + filterset = filtersets.FrontPortFilterSet filterset_form = forms.FrontPortFilterForm table = tables.FrontPortTable action_buttons = ('import', 'export') @@ -1987,7 +1987,7 @@ class FrontPortBulkImportView(generic.BulkImportView): class FrontPortBulkEditView(generic.BulkEditView): queryset = FrontPort.objects.all() - filterset = filters.FrontPortFilterSet + filterset = filtersets.FrontPortFilterSet table = tables.FrontPortTable form = forms.FrontPortBulkEditForm @@ -2002,7 +2002,7 @@ class FrontPortBulkDisconnectView(BulkDisconnectView): class FrontPortBulkDeleteView(generic.BulkDeleteView): queryset = FrontPort.objects.all() - filterset = filters.FrontPortFilterSet + filterset = filtersets.FrontPortFilterSet table = tables.FrontPortTable @@ -2012,7 +2012,7 @@ class FrontPortBulkDeleteView(generic.BulkDeleteView): class RearPortListView(generic.ObjectListView): queryset = RearPort.objects.all() - filterset = filters.RearPortFilterSet + filterset = filtersets.RearPortFilterSet filterset_form = forms.RearPortFilterForm table = tables.RearPortTable action_buttons = ('import', 'export') @@ -2047,7 +2047,7 @@ class RearPortBulkImportView(generic.BulkImportView): class RearPortBulkEditView(generic.BulkEditView): queryset = RearPort.objects.all() - filterset = filters.RearPortFilterSet + filterset = filtersets.RearPortFilterSet table = tables.RearPortTable form = forms.RearPortBulkEditForm @@ -2062,7 +2062,7 @@ class RearPortBulkDisconnectView(BulkDisconnectView): class RearPortBulkDeleteView(generic.BulkDeleteView): queryset = RearPort.objects.all() - filterset = filters.RearPortFilterSet + filterset = filtersets.RearPortFilterSet table = tables.RearPortTable @@ -2072,7 +2072,7 @@ class RearPortBulkDeleteView(generic.BulkDeleteView): class DeviceBayListView(generic.ObjectListView): queryset = DeviceBay.objects.all() - filterset = filters.DeviceBayFilterSet + filterset = filtersets.DeviceBayFilterSet filterset_form = forms.DeviceBayFilterForm table = tables.DeviceBayTable action_buttons = ('import', 'export') @@ -2172,7 +2172,7 @@ class DeviceBayBulkImportView(generic.BulkImportView): class DeviceBayBulkEditView(generic.BulkEditView): queryset = DeviceBay.objects.all() - filterset = filters.DeviceBayFilterSet + filterset = filtersets.DeviceBayFilterSet table = tables.DeviceBayTable form = forms.DeviceBayBulkEditForm @@ -2183,7 +2183,7 @@ class DeviceBayBulkRenameView(generic.BulkRenameView): class DeviceBayBulkDeleteView(generic.BulkDeleteView): queryset = DeviceBay.objects.all() - filterset = filters.DeviceBayFilterSet + filterset = filtersets.DeviceBayFilterSet table = tables.DeviceBayTable @@ -2193,7 +2193,7 @@ class DeviceBayBulkDeleteView(generic.BulkDeleteView): class InventoryItemListView(generic.ObjectListView): queryset = InventoryItem.objects.all() - filterset = filters.InventoryItemFilterSet + filterset = filtersets.InventoryItemFilterSet filterset_form = forms.InventoryItemFilterForm table = tables.InventoryItemTable action_buttons = ('import', 'export') @@ -2227,7 +2227,7 @@ class InventoryItemBulkImportView(generic.BulkImportView): class InventoryItemBulkEditView(generic.BulkEditView): queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer') - filterset = filters.InventoryItemFilterSet + filterset = filtersets.InventoryItemFilterSet table = tables.InventoryItemTable form = forms.InventoryItemBulkEditForm @@ -2252,7 +2252,7 @@ class DeviceBulkAddConsolePortView(generic.BulkComponentCreateView): form = forms.ConsolePortBulkCreateForm queryset = ConsolePort.objects.all() model_form = forms.ConsolePortForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2263,7 +2263,7 @@ class DeviceBulkAddConsoleServerPortView(generic.BulkComponentCreateView): form = forms.ConsoleServerPortBulkCreateForm queryset = ConsoleServerPort.objects.all() model_form = forms.ConsoleServerPortForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2274,7 +2274,7 @@ class DeviceBulkAddPowerPortView(generic.BulkComponentCreateView): form = forms.PowerPortBulkCreateForm queryset = PowerPort.objects.all() model_form = forms.PowerPortForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2285,7 +2285,7 @@ class DeviceBulkAddPowerOutletView(generic.BulkComponentCreateView): form = forms.PowerOutletBulkCreateForm queryset = PowerOutlet.objects.all() model_form = forms.PowerOutletForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2296,7 +2296,7 @@ class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView): form = forms.InterfaceBulkCreateForm queryset = Interface.objects.all() model_form = forms.InterfaceForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2307,7 +2307,7 @@ class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView): # form = forms.FrontPortBulkCreateForm # queryset = FrontPort.objects.all() # model_form = forms.FrontPortForm -# filterset = filters.DeviceFilterSet +# filterset = filtersets.DeviceFilterSet # table = tables.DeviceTable # default_return_url = 'dcim:device_list' @@ -2318,7 +2318,7 @@ class DeviceBulkAddRearPortView(generic.BulkComponentCreateView): form = forms.RearPortBulkCreateForm queryset = RearPort.objects.all() model_form = forms.RearPortForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2329,7 +2329,7 @@ class DeviceBulkAddDeviceBayView(generic.BulkComponentCreateView): form = forms.DeviceBayBulkCreateForm queryset = DeviceBay.objects.all() model_form = forms.DeviceBayForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2340,7 +2340,7 @@ class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView): form = forms.InventoryItemBulkCreateForm queryset = InventoryItem.objects.all() model_form = forms.InventoryItemForm - filterset = filters.DeviceFilterSet + filterset = filtersets.DeviceFilterSet table = tables.DeviceTable default_return_url = 'dcim:device_list' @@ -2351,7 +2351,7 @@ class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView): class CableListView(generic.ObjectListView): queryset = Cable.objects.all() - filterset = filters.CableFilterSet + filterset = filtersets.CableFilterSet filterset_form = forms.CableFilterForm table = tables.CableTable action_buttons = ('import', 'export') @@ -2484,14 +2484,14 @@ class CableBulkImportView(generic.BulkImportView): class CableBulkEditView(generic.BulkEditView): queryset = Cable.objects.prefetch_related('termination_a', 'termination_b') - filterset = filters.CableFilterSet + filterset = filtersets.CableFilterSet table = tables.CableTable form = forms.CableBulkEditForm class CableBulkDeleteView(generic.BulkDeleteView): queryset = Cable.objects.prefetch_related('termination_a', 'termination_b') - filterset = filters.CableFilterSet + filterset = filtersets.CableFilterSet table = tables.CableTable @@ -2501,7 +2501,7 @@ class CableBulkDeleteView(generic.BulkDeleteView): class ConsoleConnectionsListView(generic.ObjectListView): queryset = ConsolePort.objects.filter(_path__isnull=False).order_by('device') - filterset = filters.ConsoleConnectionFilterSet + filterset = filtersets.ConsoleConnectionFilterSet filterset_form = forms.ConsoleConnectionFilterForm table = tables.ConsoleConnectionTable template_name = 'dcim/connections_list.html' @@ -2531,7 +2531,7 @@ class ConsoleConnectionsListView(generic.ObjectListView): class PowerConnectionsListView(generic.ObjectListView): queryset = PowerPort.objects.filter(_path__isnull=False).order_by('device') - filterset = filters.PowerConnectionFilterSet + filterset = filtersets.PowerConnectionFilterSet filterset_form = forms.PowerConnectionFilterForm table = tables.PowerConnectionTable template_name = 'dcim/connections_list.html' @@ -2565,7 +2565,7 @@ class InterfaceConnectionsListView(generic.ObjectListView): _path__isnull=False, pk__lt=F('_path__destination_id') ).order_by('device') - filterset = filters.InterfaceConnectionFilterSet + filterset = filtersets.InterfaceConnectionFilterSet filterset_form = forms.InterfaceConnectionFilterForm table = tables.InterfaceConnectionTable template_name = 'dcim/connections_list.html' @@ -2604,7 +2604,7 @@ class VirtualChassisListView(generic.ObjectListView): member_count=count_related(Device, 'virtual_chassis') ) table = tables.VirtualChassisTable - filterset = filters.VirtualChassisFilterSet + filterset = filtersets.VirtualChassisFilterSet filterset_form = forms.VirtualChassisFilterForm @@ -2812,14 +2812,14 @@ class VirtualChassisBulkImportView(generic.BulkImportView): class VirtualChassisBulkEditView(generic.BulkEditView): queryset = VirtualChassis.objects.all() - filterset = filters.VirtualChassisFilterSet + filterset = filtersets.VirtualChassisFilterSet table = tables.VirtualChassisTable form = forms.VirtualChassisBulkEditForm class VirtualChassisBulkDeleteView(generic.BulkDeleteView): queryset = VirtualChassis.objects.all() - filterset = filters.VirtualChassisFilterSet + filterset = filtersets.VirtualChassisFilterSet table = tables.VirtualChassisTable @@ -2833,7 +2833,7 @@ class PowerPanelListView(generic.ObjectListView): ).annotate( powerfeed_count=count_related(PowerFeed, 'power_panel') ) - filterset = filters.PowerPanelFilterSet + filterset = filtersets.PowerPanelFilterSet filterset_form = forms.PowerPanelFilterForm table = tables.PowerPanelTable @@ -2873,7 +2873,7 @@ class PowerPanelBulkImportView(generic.BulkImportView): class PowerPanelBulkEditView(generic.BulkEditView): queryset = PowerPanel.objects.prefetch_related('site', 'location') - filterset = filters.PowerPanelFilterSet + filterset = filtersets.PowerPanelFilterSet table = tables.PowerPanelTable form = forms.PowerPanelBulkEditForm @@ -2884,7 +2884,7 @@ class PowerPanelBulkDeleteView(generic.BulkDeleteView): ).annotate( powerfeed_count=count_related(PowerFeed, 'power_panel') ) - filterset = filters.PowerPanelFilterSet + filterset = filtersets.PowerPanelFilterSet table = tables.PowerPanelTable @@ -2894,7 +2894,7 @@ class PowerPanelBulkDeleteView(generic.BulkDeleteView): class PowerFeedListView(generic.ObjectListView): queryset = PowerFeed.objects.all() - filterset = filters.PowerFeedFilterSet + filterset = filtersets.PowerFeedFilterSet filterset_form = forms.PowerFeedFilterForm table = tables.PowerFeedTable @@ -2920,7 +2920,7 @@ class PowerFeedBulkImportView(generic.BulkImportView): class PowerFeedBulkEditView(generic.BulkEditView): queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack') - filterset = filters.PowerFeedFilterSet + filterset = filtersets.PowerFeedFilterSet table = tables.PowerFeedTable form = forms.PowerFeedBulkEditForm @@ -2931,5 +2931,5 @@ class PowerFeedBulkDisconnectView(BulkDisconnectView): class PowerFeedBulkDeleteView(generic.BulkDeleteView): queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack') - filterset = filters.PowerFeedFilterSet + filterset = filtersets.PowerFeedFilterSet table = tables.PowerFeedTable diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index 3757d73f3..aef2046fd 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -6,6 +6,7 @@ from .choices import * __all__ = ( 'CustomFieldFilter', + 'TagFilter', ) EXACT_FILTER_TYPES = ( diff --git a/netbox/extras/tests/test_customfields.py b/netbox/extras/tests/test_customfields.py index d1725ac9d..c14424ba6 100644 --- a/netbox/extras/tests/test_customfields.py +++ b/netbox/extras/tests/test_customfields.py @@ -3,7 +3,7 @@ from django.core.exceptions import ValidationError from django.urls import reverse from rest_framework import status -from dcim.filters import SiteFilterSet +from dcim.filtersets import SiteFilterSet from dcim.forms import SiteCSVForm from dcim.models import Site, Rack from extras.choices import * diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index 1e1177772..f3f1335f7 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -10,7 +10,7 @@ from rest_framework.response import Response from rest_framework.routers import APIRootView from extras.api.views import CustomFieldModelViewSet -from ipam import filters +from ipam import filtersets from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF from netbox.api.views import ModelViewSet from utilities.constants import ADVISORY_LOCK_KEYS @@ -38,7 +38,7 @@ class VRFViewSet(CustomFieldModelViewSet): prefix_count=count_related(Prefix, 'vrf') ) serializer_class = serializers.VRFSerializer - filterset_class = filters.VRFFilterSet + filterset_class = filtersets.VRFFilterSet # @@ -48,7 +48,7 @@ class VRFViewSet(CustomFieldModelViewSet): class RouteTargetViewSet(CustomFieldModelViewSet): queryset = RouteTarget.objects.prefetch_related('tenant').prefetch_related('tags') serializer_class = serializers.RouteTargetSerializer - filterset_class = filters.RouteTargetFilterSet + filterset_class = filtersets.RouteTargetFilterSet # @@ -60,7 +60,7 @@ class RIRViewSet(CustomFieldModelViewSet): aggregate_count=count_related(Aggregate, 'rir') ) serializer_class = serializers.RIRSerializer - filterset_class = filters.RIRFilterSet + filterset_class = filtersets.RIRFilterSet # @@ -70,7 +70,7 @@ class RIRViewSet(CustomFieldModelViewSet): class AggregateViewSet(CustomFieldModelViewSet): queryset = Aggregate.objects.prefetch_related('rir').prefetch_related('tags') serializer_class = serializers.AggregateSerializer - filterset_class = filters.AggregateFilterSet + filterset_class = filtersets.AggregateFilterSet # @@ -83,7 +83,7 @@ class RoleViewSet(CustomFieldModelViewSet): vlan_count=count_related(VLAN, 'role') ) serializer_class = serializers.RoleSerializer - filterset_class = filters.RoleFilterSet + filterset_class = filtersets.RoleFilterSet # @@ -95,7 +95,7 @@ class PrefixViewSet(CustomFieldModelViewSet): 'site', 'vrf__tenant', 'tenant', 'vlan', 'role', 'tags' ) serializer_class = serializers.PrefixSerializer - filterset_class = filters.PrefixFilterSet + filterset_class = filtersets.PrefixFilterSet def get_serializer_class(self): if self.action == "available_prefixes" and self.request.method == "POST": @@ -275,7 +275,7 @@ class IPAddressViewSet(CustomFieldModelViewSet): 'vrf__tenant', 'tenant', 'nat_inside', 'nat_outside', 'tags', 'assigned_object' ) serializer_class = serializers.IPAddressSerializer - filterset_class = filters.IPAddressFilterSet + filterset_class = filtersets.IPAddressFilterSet # @@ -287,7 +287,7 @@ class VLANGroupViewSet(CustomFieldModelViewSet): vlan_count=count_related(VLAN, 'group') ) serializer_class = serializers.VLANGroupSerializer - filterset_class = filters.VLANGroupFilterSet + filterset_class = filtersets.VLANGroupFilterSet # @@ -301,7 +301,7 @@ class VLANViewSet(CustomFieldModelViewSet): prefix_count=count_related(Prefix, 'vlan') ) serializer_class = serializers.VLANSerializer - filterset_class = filters.VLANFilterSet + filterset_class = filtersets.VLANFilterSet # @@ -313,4 +313,4 @@ class ServiceViewSet(ModelViewSet): 'device', 'virtual_machine', 'tags', 'ipaddresses' ) serializer_class = serializers.ServiceSerializer - filterset_class = filters.ServiceFilterSet + filterset_class = filtersets.ServiceFilterSet diff --git a/netbox/ipam/filters.py b/netbox/ipam/filtersets.py similarity index 99% rename from netbox/ipam/filters.py rename to netbox/ipam/filtersets.py index db1b76f31..a4c6d0415 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filtersets.py @@ -7,7 +7,7 @@ from netaddr.core import AddrFormatError from dcim.models import Device, Interface, Region, Site, SiteGroup from extras.filters import TagFilter -from tenancy.filters import TenancyFilterSet +from tenancy.filtersets import TenancyFilterSet from utilities.filters import ( ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter, ) diff --git a/netbox/ipam/tests/test_filters.py b/netbox/ipam/tests/test_filters.py index 3ea54209c..d0b59ae39 100644 --- a/netbox/ipam/tests/test_filters.py +++ b/netbox/ipam/tests/test_filters.py @@ -2,7 +2,7 @@ from django.test import TestCase from dcim.models import Device, DeviceRole, DeviceType, Interface, Location, Manufacturer, Rack, Region, Site, SiteGroup from ipam.choices import * -from ipam.filters import * +from ipam.filtersets import * from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from tenancy.models import Tenant, TenantGroup diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index f7da1f583..95aa8c3c1 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -7,7 +7,7 @@ from netbox.views import generic from utilities.tables import paginate_table from utilities.utils import count_related from virtualization.models import VirtualMachine, VMInterface -from . import filters, forms, tables +from . import filtersets, forms, tables from .constants import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF from .utils import add_available_ipaddresses, add_available_prefixes, add_available_vlans @@ -19,7 +19,7 @@ from .utils import add_available_ipaddresses, add_available_prefixes, add_availa class VRFListView(generic.ObjectListView): queryset = VRF.objects.all() - filterset = filters.VRFFilterSet + filterset = filtersets.VRFFilterSet filterset_form = forms.VRFFilterForm table = tables.VRFTable @@ -65,14 +65,14 @@ class VRFBulkImportView(generic.BulkImportView): class VRFBulkEditView(generic.BulkEditView): queryset = VRF.objects.prefetch_related('tenant') - filterset = filters.VRFFilterSet + filterset = filtersets.VRFFilterSet table = tables.VRFTable form = forms.VRFBulkEditForm class VRFBulkDeleteView(generic.BulkDeleteView): queryset = VRF.objects.prefetch_related('tenant') - filterset = filters.VRFFilterSet + filterset = filtersets.VRFFilterSet table = tables.VRFTable @@ -82,7 +82,7 @@ class VRFBulkDeleteView(generic.BulkDeleteView): class RouteTargetListView(generic.ObjectListView): queryset = RouteTarget.objects.all() - filterset = filters.RouteTargetFilterSet + filterset = filtersets.RouteTargetFilterSet filterset_form = forms.RouteTargetFilterForm table = tables.RouteTargetTable @@ -123,14 +123,14 @@ class RouteTargetBulkImportView(generic.BulkImportView): class RouteTargetBulkEditView(generic.BulkEditView): queryset = RouteTarget.objects.prefetch_related('tenant') - filterset = filters.RouteTargetFilterSet + filterset = filtersets.RouteTargetFilterSet table = tables.RouteTargetTable form = forms.RouteTargetBulkEditForm class RouteTargetBulkDeleteView(generic.BulkDeleteView): queryset = RouteTarget.objects.prefetch_related('tenant') - filterset = filters.RouteTargetFilterSet + filterset = filtersets.RouteTargetFilterSet table = tables.RouteTargetTable @@ -142,7 +142,7 @@ class RIRListView(generic.ObjectListView): queryset = RIR.objects.annotate( aggregate_count=count_related(Aggregate, 'rir') ) - filterset = filters.RIRFilterSet + filterset = filtersets.RIRFilterSet filterset_form = forms.RIRFilterForm table = tables.RIRTable template_name = 'ipam/rir_list.html' @@ -184,7 +184,7 @@ class RIRBulkEditView(generic.BulkEditView): queryset = RIR.objects.annotate( aggregate_count=count_related(Aggregate, 'rir') ) - filterset = filters.RIRFilterSet + filterset = filtersets.RIRFilterSet table = tables.RIRTable form = forms.RIRBulkEditForm @@ -193,7 +193,7 @@ class RIRBulkDeleteView(generic.BulkDeleteView): queryset = RIR.objects.annotate( aggregate_count=count_related(Aggregate, 'rir') ) - filterset = filters.RIRFilterSet + filterset = filtersets.RIRFilterSet table = tables.RIRTable @@ -205,7 +205,7 @@ class AggregateListView(generic.ObjectListView): queryset = Aggregate.objects.annotate( child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ()) ) - filterset = filters.AggregateFilterSet + filterset = filtersets.AggregateFilterSet filterset_form = forms.AggregateFilterForm table = tables.AggregateDetailTable template_name = 'ipam/aggregate_list.html' @@ -280,14 +280,14 @@ class AggregateBulkImportView(generic.BulkImportView): class AggregateBulkEditView(generic.BulkEditView): queryset = Aggregate.objects.prefetch_related('rir') - filterset = filters.AggregateFilterSet + filterset = filtersets.AggregateFilterSet table = tables.AggregateTable form = forms.AggregateBulkEditForm class AggregateBulkDeleteView(generic.BulkDeleteView): queryset = Aggregate.objects.prefetch_related('rir') - filterset = filters.AggregateFilterSet + filterset = filtersets.AggregateFilterSet table = tables.AggregateTable @@ -337,7 +337,7 @@ class RoleBulkImportView(generic.BulkImportView): class RoleBulkEditView(generic.BulkEditView): queryset = Role.objects.all() - filterset = filters.RoleFilterSet + filterset = filtersets.RoleFilterSet table = tables.RoleTable form = forms.RoleBulkEditForm @@ -353,7 +353,7 @@ class RoleBulkDeleteView(generic.BulkDeleteView): class PrefixListView(generic.ObjectListView): queryset = Prefix.objects.annotate_tree() - filterset = filters.PrefixFilterSet + filterset = filtersets.PrefixFilterSet filterset_form = forms.PrefixFilterForm table = tables.PrefixDetailTable template_name = 'ipam/prefix_list.html' @@ -493,14 +493,14 @@ class PrefixBulkImportView(generic.BulkImportView): class PrefixBulkEditView(generic.BulkEditView): queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role') - filterset = filters.PrefixFilterSet + filterset = filtersets.PrefixFilterSet table = tables.PrefixTable form = forms.PrefixBulkEditForm class PrefixBulkDeleteView(generic.BulkDeleteView): queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role') - filterset = filters.PrefixFilterSet + filterset = filtersets.PrefixFilterSet table = tables.PrefixTable @@ -510,7 +510,7 @@ class PrefixBulkDeleteView(generic.BulkDeleteView): class IPAddressListView(generic.ObjectListView): queryset = IPAddress.objects.all() - filterset = filters.IPAddressFilterSet + filterset = filtersets.IPAddressFilterSet filterset_form = forms.IPAddressFilterForm table = tables.IPAddressDetailTable @@ -613,7 +613,7 @@ class IPAddressAssignView(generic.ObjectView): addresses = self.queryset.prefetch_related('vrf', 'tenant') # Limit to 100 results - addresses = filters.IPAddressFilterSet(request.POST, addresses).qs[:100] + addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100] table = tables.IPAddressAssignTable(addresses) return render(request, 'ipam/ipaddress_assign.html', { @@ -643,14 +643,14 @@ class IPAddressBulkImportView(generic.BulkImportView): class IPAddressBulkEditView(generic.BulkEditView): queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant') - filterset = filters.IPAddressFilterSet + filterset = filtersets.IPAddressFilterSet table = tables.IPAddressTable form = forms.IPAddressBulkEditForm class IPAddressBulkDeleteView(generic.BulkDeleteView): queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant') - filterset = filters.IPAddressFilterSet + filterset = filtersets.IPAddressFilterSet table = tables.IPAddressTable @@ -662,7 +662,7 @@ class VLANGroupListView(generic.ObjectListView): queryset = VLANGroup.objects.annotate( vlan_count=count_related(VLAN, 'group') ) - filterset = filters.VLANGroupFilterSet + filterset = filtersets.VLANGroupFilterSet filterset_form = forms.VLANGroupFilterForm table = tables.VLANGroupTable @@ -718,7 +718,7 @@ class VLANGroupBulkEditView(generic.BulkEditView): queryset = VLANGroup.objects.annotate( vlan_count=count_related(VLAN, 'group') ) - filterset = filters.VLANGroupFilterSet + filterset = filtersets.VLANGroupFilterSet table = tables.VLANGroupTable form = forms.VLANGroupBulkEditForm @@ -727,7 +727,7 @@ class VLANGroupBulkDeleteView(generic.BulkDeleteView): queryset = VLANGroup.objects.annotate( vlan_count=count_related(VLAN, 'group') ) - filterset = filters.VLANGroupFilterSet + filterset = filtersets.VLANGroupFilterSet table = tables.VLANGroupTable @@ -737,7 +737,7 @@ class VLANGroupBulkDeleteView(generic.BulkDeleteView): class VLANListView(generic.ObjectListView): queryset = VLAN.objects.all() - filterset = filters.VLANFilterSet + filterset = filtersets.VLANFilterSet filterset_form = forms.VLANFilterForm table = tables.VLANDetailTable @@ -805,14 +805,14 @@ class VLANBulkImportView(generic.BulkImportView): class VLANBulkEditView(generic.BulkEditView): queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role') - filterset = filters.VLANFilterSet + filterset = filtersets.VLANFilterSet table = tables.VLANTable form = forms.VLANBulkEditForm class VLANBulkDeleteView(generic.BulkDeleteView): queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role') - filterset = filters.VLANFilterSet + filterset = filtersets.VLANFilterSet table = tables.VLANTable @@ -822,7 +822,7 @@ class VLANBulkDeleteView(generic.BulkDeleteView): class ServiceListView(generic.ObjectListView): queryset = Service.objects.all() - filterset = filters.ServiceFilterSet + filterset = filtersets.ServiceFilterSet filterset_form = forms.ServiceFilterForm table = tables.ServiceTable action_buttons = ('import', 'export') @@ -863,12 +863,12 @@ class ServiceDeleteView(generic.ObjectDeleteView): class ServiceBulkEditView(generic.BulkEditView): queryset = Service.objects.prefetch_related('device', 'virtual_machine') - filterset = filters.ServiceFilterSet + filterset = filtersets.ServiceFilterSet table = tables.ServiceTable form = forms.ServiceBulkEditForm class ServiceBulkDeleteView(generic.BulkDeleteView): queryset = Service.objects.prefetch_related('device', 'virtual_machine') - filterset = filters.ServiceFilterSet + filterset = filtersets.ServiceFilterSet table = tables.ServiceTable diff --git a/netbox/netbox/constants.py b/netbox/netbox/constants.py index 5568f4e70..b6da0b2de 100644 --- a/netbox/netbox/constants.py +++ b/netbox/netbox/constants.py @@ -1,9 +1,9 @@ from collections import OrderedDict -from circuits.filters import CircuitFilterSet, ProviderFilterSet, ProviderNetworkFilterSet +from circuits.filtersets import CircuitFilterSet, ProviderFilterSet, ProviderNetworkFilterSet from circuits.models import Circuit, ProviderNetwork, Provider from circuits.tables import CircuitTable, ProviderNetworkTable, ProviderTable -from dcim.filters import ( +from dcim.filtersets import ( CableFilterSet, DeviceFilterSet, DeviceTypeFilterSet, PowerFeedFilterSet, RackFilterSet, LocationFilterSet, SiteFilterSet, VirtualChassisFilterSet, ) @@ -12,17 +12,17 @@ from dcim.tables import ( CableTable, DeviceTable, DeviceTypeTable, PowerFeedTable, RackTable, LocationTable, SiteTable, VirtualChassisTable, ) -from ipam.filters import AggregateFilterSet, IPAddressFilterSet, PrefixFilterSet, VLANFilterSet, VRFFilterSet +from ipam.filtersets import AggregateFilterSet, IPAddressFilterSet, PrefixFilterSet, VLANFilterSet, VRFFilterSet from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF from ipam.tables import AggregateTable, IPAddressTable, PrefixTable, VLANTable, VRFTable -from secrets.filters import SecretFilterSet +from secrets.filtersets import SecretFilterSet from secrets.models import Secret from secrets.tables import SecretTable -from tenancy.filters import TenantFilterSet +from tenancy.filtersets import TenantFilterSet from tenancy.models import Tenant from tenancy.tables import TenantTable from utilities.utils import count_related -from virtualization.filters import ClusterFilterSet, VirtualMachineFilterSet +from virtualization.filtersets import ClusterFilterSet, VirtualMachineFilterSet from virtualization.models import Cluster, VirtualMachine from virtualization.tables import ClusterTable, VirtualMachineDetailTable diff --git a/netbox/secrets/api/views.py b/netbox/secrets/api/views.py index 3650abd30..7982d29f1 100644 --- a/netbox/secrets/api/views.py +++ b/netbox/secrets/api/views.py @@ -10,7 +10,7 @@ from rest_framework.viewsets import ViewSet from extras.api.views import CustomFieldModelViewSet from netbox.api.views import ModelViewSet -from secrets import filters +from secrets import filtersets from secrets.exceptions import InvalidKey from secrets.models import Secret, SecretRole, SessionKey, UserKey from utilities.utils import count_related @@ -39,7 +39,7 @@ class SecretRoleViewSet(CustomFieldModelViewSet): secret_count=count_related(Secret, 'role') ) serializer_class = serializers.SecretRoleSerializer - filterset_class = filters.SecretRoleFilterSet + filterset_class = filtersets.SecretRoleFilterSet # @@ -49,7 +49,7 @@ class SecretRoleViewSet(CustomFieldModelViewSet): class SecretViewSet(ModelViewSet): queryset = Secret.objects.prefetch_related('role', 'tags') serializer_class = serializers.SecretSerializer - filterset_class = filters.SecretFilterSet + filterset_class = filtersets.SecretFilterSet master_key = None diff --git a/netbox/secrets/filters.py b/netbox/secrets/filtersets.py similarity index 100% rename from netbox/secrets/filters.py rename to netbox/secrets/filtersets.py diff --git a/netbox/secrets/tests/test_filters.py b/netbox/secrets/tests/test_filters.py index 0be1ef594..1d9d18f37 100644 --- a/netbox/secrets/tests/test_filters.py +++ b/netbox/secrets/tests/test_filters.py @@ -1,7 +1,7 @@ from django.test import TestCase from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site -from secrets.filters import * +from secrets.filtersets import * from secrets.models import Secret, SecretRole from virtualization.models import Cluster, ClusterType, VirtualMachine diff --git a/netbox/secrets/views.py b/netbox/secrets/views.py index 57d64f064..091e16224 100644 --- a/netbox/secrets/views.py +++ b/netbox/secrets/views.py @@ -2,14 +2,14 @@ import base64 import logging from django.contrib import messages -from django.shortcuts import get_object_or_404, redirect, render +from django.shortcuts import redirect, render from django.utils.html import escape from django.utils.safestring import mark_safe from netbox.views import generic from utilities.tables import paginate_table from utilities.utils import count_related -from . import filters, forms, tables +from . import filtersets, forms, tables from .models import SecretRole, Secret, SessionKey, UserKey @@ -70,7 +70,7 @@ class SecretRoleBulkEditView(generic.BulkEditView): queryset = SecretRole.objects.annotate( secret_count=count_related(Secret, 'role') ) - filterset = filters.SecretRoleFilterSet + filterset = filtersets.SecretRoleFilterSet table = tables.SecretRoleTable form = forms.SecretRoleBulkEditForm @@ -88,7 +88,7 @@ class SecretRoleBulkDeleteView(generic.BulkDeleteView): class SecretListView(generic.ObjectListView): queryset = Secret.objects.all() - filterset = filters.SecretFilterSet + filterset = filtersets.SecretFilterSet filterset_form = forms.SecretFilterForm table = tables.SecretTable action_buttons = ('import', 'export') @@ -220,12 +220,12 @@ class SecretBulkImportView(generic.BulkImportView): class SecretBulkEditView(generic.BulkEditView): queryset = Secret.objects.prefetch_related('role') - filterset = filters.SecretFilterSet + filterset = filtersets.SecretFilterSet table = tables.SecretTable form = forms.SecretBulkEditForm class SecretBulkDeleteView(generic.BulkDeleteView): queryset = Secret.objects.prefetch_related('role') - filterset = filters.SecretFilterSet + filterset = filtersets.SecretFilterSet table = tables.SecretTable diff --git a/netbox/tenancy/api/views.py b/netbox/tenancy/api/views.py index 3b57e1a02..2e049135d 100644 --- a/netbox/tenancy/api/views.py +++ b/netbox/tenancy/api/views.py @@ -4,7 +4,7 @@ from circuits.models import Circuit from dcim.models import Device, Rack, Site from extras.api.views import CustomFieldModelViewSet from ipam.models import IPAddress, Prefix, VLAN, VRF -from tenancy import filters +from tenancy import filtersets from tenancy.models import Tenant, TenantGroup from utilities.utils import count_related from virtualization.models import VirtualMachine @@ -32,7 +32,7 @@ class TenantGroupViewSet(CustomFieldModelViewSet): cumulative=True ) serializer_class = serializers.TenantGroupSerializer - filterset_class = filters.TenantGroupFilterSet + filterset_class = filtersets.TenantGroupFilterSet # @@ -54,4 +54,4 @@ class TenantViewSet(CustomFieldModelViewSet): vrf_count=count_related(VRF, 'tenant') ) serializer_class = serializers.TenantSerializer - filterset_class = filters.TenantFilterSet + filterset_class = filtersets.TenantFilterSet diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filtersets.py similarity index 100% rename from netbox/tenancy/filters.py rename to netbox/tenancy/filtersets.py diff --git a/netbox/tenancy/tests/test_filters.py b/netbox/tenancy/tests/test_filters.py index c78b25083..32c9cd186 100644 --- a/netbox/tenancy/tests/test_filters.py +++ b/netbox/tenancy/tests/test_filters.py @@ -1,6 +1,6 @@ from django.test import TestCase -from tenancy.filters import * +from tenancy.filtersets import * from tenancy.models import Tenant, TenantGroup diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 206ff6c7a..45dffb3c0 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -4,7 +4,7 @@ from ipam.models import IPAddress, Prefix, VLAN, VRF from netbox.views import generic from utilities.tables import paginate_table from virtualization.models import VirtualMachine, Cluster -from . import filters, forms, tables +from . import filtersets, forms, tables from .models import Tenant, TenantGroup @@ -63,7 +63,7 @@ class TenantGroupBulkEditView(generic.BulkEditView): 'tenant_count', cumulative=True ) - filterset = filters.TenantGroupFilterSet + filterset = filtersets.TenantGroupFilterSet table = tables.TenantGroupTable form = forms.TenantGroupBulkEditForm @@ -85,7 +85,7 @@ class TenantGroupBulkDeleteView(generic.BulkDeleteView): class TenantListView(generic.ObjectListView): queryset = Tenant.objects.all() - filterset = filters.TenantFilterSet + filterset = filtersets.TenantFilterSet filterset_form = forms.TenantFilterForm table = tables.TenantTable @@ -130,12 +130,12 @@ class TenantBulkImportView(generic.BulkImportView): class TenantBulkEditView(generic.BulkEditView): queryset = Tenant.objects.prefetch_related('group') - filterset = filters.TenantFilterSet + filterset = filtersets.TenantFilterSet table = tables.TenantTable form = forms.TenantBulkEditForm class TenantBulkDeleteView(generic.BulkDeleteView): queryset = Tenant.objects.prefetch_related('group') - filterset = filters.TenantFilterSet + filterset = filtersets.TenantFilterSet table = tables.TenantTable diff --git a/netbox/users/api/views.py b/netbox/users/api/views.py index 7773e54f4..b0443b87e 100644 --- a/netbox/users/api/views.py +++ b/netbox/users/api/views.py @@ -6,7 +6,7 @@ from rest_framework.routers import APIRootView from rest_framework.viewsets import ViewSet from netbox.api.views import ModelViewSet -from users import filters +from users import filtersets from users.models import ObjectPermission, UserConfig from utilities.querysets import RestrictedQuerySet from utilities.utils import deepmerge @@ -28,13 +28,13 @@ class UsersRootView(APIRootView): class UserViewSet(ModelViewSet): queryset = RestrictedQuerySet(model=User).prefetch_related('groups').order_by('username') serializer_class = serializers.UserSerializer - filterset_class = filters.UserFilterSet + filterset_class = filtersets.UserFilterSet class GroupViewSet(ModelViewSet): queryset = RestrictedQuerySet(model=Group).annotate(user_count=Count('user')).order_by('name') serializer_class = serializers.GroupSerializer - filterset_class = filters.GroupFilterSet + filterset_class = filtersets.GroupFilterSet # @@ -44,7 +44,7 @@ class GroupViewSet(ModelViewSet): class ObjectPermissionViewSet(ModelViewSet): queryset = ObjectPermission.objects.prefetch_related('object_types', 'groups', 'users') serializer_class = serializers.ObjectPermissionSerializer - filterset_class = filters.ObjectPermissionFilterSet + filterset_class = filtersets.ObjectPermissionFilterSet # diff --git a/netbox/users/filters.py b/netbox/users/filtersets.py similarity index 100% rename from netbox/users/filters.py rename to netbox/users/filtersets.py diff --git a/netbox/users/tests/test_filters.py b/netbox/users/tests/test_filters.py index c3774927c..2a3a8e24f 100644 --- a/netbox/users/tests/test_filters.py +++ b/netbox/users/tests/test_filters.py @@ -2,7 +2,7 @@ from django.contrib.auth.models import Group, User from django.contrib.contenttypes.models import ContentType from django.test import TestCase -from users.filters import GroupFilterSet, ObjectPermissionFilterSet, UserFilterSet +from users.filtersets import GroupFilterSet, ObjectPermissionFilterSet, UserFilterSet from users.models import ObjectPermission diff --git a/netbox/utilities/tests/test_filters.py b/netbox/utilities/tests/test_filters.py index 21f020fb4..6be611885 100644 --- a/netbox/utilities/tests/test_filters.py +++ b/netbox/utilities/tests/test_filters.py @@ -7,7 +7,7 @@ from taggit.managers import TaggableManager from dcim.choices import * from dcim.fields import MACAddressField -from dcim.filters import DeviceFilterSet, SiteFilterSet +from dcim.filtersets import DeviceFilterSet, SiteFilterSet from dcim.models import ( Device, DeviceRole, DeviceType, Interface, Manufacturer, Platform, Rack, Region, Site ) diff --git a/netbox/virtualization/api/views.py b/netbox/virtualization/api/views.py index 1c4371ed0..8eebd2120 100644 --- a/netbox/virtualization/api/views.py +++ b/netbox/virtualization/api/views.py @@ -3,7 +3,7 @@ from rest_framework.routers import APIRootView from dcim.models import Device from extras.api.views import ConfigContextQuerySetMixin, CustomFieldModelViewSet, ModelViewSet from utilities.utils import count_related -from virtualization import filters +from virtualization import filtersets from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from . import serializers @@ -25,7 +25,7 @@ class ClusterTypeViewSet(CustomFieldModelViewSet): cluster_count=count_related(Cluster, 'type') ) serializer_class = serializers.ClusterTypeSerializer - filterset_class = filters.ClusterTypeFilterSet + filterset_class = filtersets.ClusterTypeFilterSet class ClusterGroupViewSet(CustomFieldModelViewSet): @@ -33,7 +33,7 @@ class ClusterGroupViewSet(CustomFieldModelViewSet): cluster_count=count_related(Cluster, 'group') ) serializer_class = serializers.ClusterGroupSerializer - filterset_class = filters.ClusterGroupFilterSet + filterset_class = filtersets.ClusterGroupFilterSet class ClusterViewSet(CustomFieldModelViewSet): @@ -44,7 +44,7 @@ class ClusterViewSet(CustomFieldModelViewSet): virtualmachine_count=count_related(VirtualMachine, 'cluster') ) serializer_class = serializers.ClusterSerializer - filterset_class = filters.ClusterFilterSet + filterset_class = filtersets.ClusterFilterSet # @@ -55,7 +55,7 @@ class VirtualMachineViewSet(ConfigContextQuerySetMixin, CustomFieldModelViewSet) queryset = VirtualMachine.objects.prefetch_related( 'cluster__site', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'tags' ) - filterset_class = filters.VirtualMachineFilterSet + filterset_class = filtersets.VirtualMachineFilterSet def get_serializer_class(self): """ @@ -83,5 +83,5 @@ class VMInterfaceViewSet(ModelViewSet): 'virtual_machine', 'parent', 'tags', 'tagged_vlans', 'ip_addresses' ) serializer_class = serializers.VMInterfaceSerializer - filterset_class = filters.VMInterfaceFilterSet + filterset_class = filtersets.VMInterfaceFilterSet brief_prefetch_fields = ['virtual_machine'] diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filtersets.py similarity index 99% rename from netbox/virtualization/filters.py rename to netbox/virtualization/filtersets.py index 6c2e0a48a..023dfb13b 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filtersets.py @@ -4,7 +4,7 @@ from django.db.models import Q from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup from extras.filters import TagFilter from extras.filtersets import LocalConfigContextFilterSet -from tenancy.filters import TenancyFilterSet +from tenancy.filtersets import TenancyFilterSet from utilities.filters import MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * diff --git a/netbox/virtualization/tests/test_filters.py b/netbox/virtualization/tests/test_filters.py index c11423663..40803cc07 100644 --- a/netbox/virtualization/tests/test_filters.py +++ b/netbox/virtualization/tests/test_filters.py @@ -4,7 +4,7 @@ from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup from ipam.models import IPAddress from tenancy.models import Tenant, TenantGroup from virtualization.choices import * -from virtualization.filters import * +from virtualization.filtersets import * from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 6b316de0e..421278d6e 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -13,7 +13,7 @@ from netbox.views import generic from secrets.models import Secret from utilities.tables import paginate_table from utilities.utils import count_related -from . import filters, forms, tables +from . import filtersets, forms, tables from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface @@ -64,7 +64,7 @@ class ClusterTypeBulkEditView(generic.BulkEditView): queryset = ClusterType.objects.annotate( cluster_count=count_related(Cluster, 'type') ) - filterset = filters.ClusterTypeFilterSet + filterset = filtersets.ClusterTypeFilterSet table = tables.ClusterTypeTable form = forms.ClusterTypeBulkEditForm @@ -125,7 +125,7 @@ class ClusterGroupBulkEditView(generic.BulkEditView): queryset = ClusterGroup.objects.annotate( cluster_count=count_related(Cluster, 'group') ) - filterset = filters.ClusterGroupFilterSet + filterset = filtersets.ClusterGroupFilterSet table = tables.ClusterGroupTable form = forms.ClusterGroupBulkEditForm @@ -148,7 +148,7 @@ class ClusterListView(generic.ObjectListView): vm_count=count_related(VirtualMachine, 'cluster') ) table = tables.ClusterTable - filterset = filters.ClusterFilterSet + filterset = filtersets.ClusterFilterSet filterset_form = forms.ClusterFilterForm @@ -205,14 +205,14 @@ class ClusterBulkImportView(generic.BulkImportView): class ClusterBulkEditView(generic.BulkEditView): queryset = Cluster.objects.prefetch_related('type', 'group', 'site') - filterset = filters.ClusterFilterSet + filterset = filtersets.ClusterFilterSet table = tables.ClusterTable form = forms.ClusterBulkEditForm class ClusterBulkDeleteView(generic.BulkDeleteView): queryset = Cluster.objects.prefetch_related('type', 'group', 'site') - filterset = filters.ClusterFilterSet + filterset = filtersets.ClusterFilterSet table = tables.ClusterTable @@ -304,7 +304,7 @@ class ClusterRemoveDevicesView(generic.ObjectEditView): class VirtualMachineListView(generic.ObjectListView): queryset = VirtualMachine.objects.all() - filterset = filters.VirtualMachineFilterSet + filterset = filtersets.VirtualMachineFilterSet filterset_form = forms.VirtualMachineFilterForm table = tables.VirtualMachineDetailTable template_name = 'virtualization/virtualmachine_list.html' @@ -388,14 +388,14 @@ class VirtualMachineBulkImportView(generic.BulkImportView): class VirtualMachineBulkEditView(generic.BulkEditView): queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role') - filterset = filters.VirtualMachineFilterSet + filterset = filtersets.VirtualMachineFilterSet table = tables.VirtualMachineTable form = forms.VirtualMachineBulkEditForm class VirtualMachineBulkDeleteView(generic.BulkDeleteView): queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role') - filterset = filters.VirtualMachineFilterSet + filterset = filtersets.VirtualMachineFilterSet table = tables.VirtualMachineTable @@ -405,7 +405,7 @@ class VirtualMachineBulkDeleteView(generic.BulkDeleteView): class VMInterfaceListView(generic.ObjectListView): queryset = VMInterface.objects.all() - filterset = filters.VMInterfaceFilterSet + filterset = filtersets.VMInterfaceFilterSet filterset_form = forms.VMInterfaceFilterForm table = tables.VMInterfaceTable action_buttons = ('export',) @@ -500,7 +500,7 @@ class VirtualMachineBulkAddInterfaceView(generic.BulkComponentCreateView): form = forms.VMInterfaceBulkCreateForm queryset = VMInterface.objects.all() model_form = forms.VMInterfaceForm - filterset = filters.VirtualMachineFilterSet + filterset = filtersets.VirtualMachineFilterSet table = tables.VirtualMachineTable def get_required_permission(self): From 3ef6284a0d1f9245c502592d1b762240a03bd32d Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 29 Apr 2021 16:53:48 -0400 Subject: [PATCH 5/5] Move base FilterSet classes under netbox core --- netbox/circuits/filtersets.py | 2 +- netbox/dcim/filtersets.py | 6 +++--- netbox/extras/filtersets.py | 2 +- netbox/ipam/filtersets.py | 2 +- netbox/{utilities => netbox}/filtersets.py | 2 +- netbox/secrets/filtersets.py | 2 +- netbox/tenancy/filtersets.py | 2 +- netbox/users/filtersets.py | 2 +- netbox/utilities/tests/test_filters.py | 2 +- netbox/virtualization/filtersets.py | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) rename netbox/{utilities => netbox}/filtersets.py (99%) diff --git a/netbox/circuits/filtersets.py b/netbox/circuits/filtersets.py index cd0b720e6..6619500cd 100644 --- a/netbox/circuits/filtersets.py +++ b/netbox/circuits/filtersets.py @@ -4,9 +4,9 @@ from django.db.models import Q from dcim.filtersets import CableTerminationFilterSet from dcim.models import Region, Site, SiteGroup from extras.filters import TagFilter +from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from tenancy.filtersets import TenancyFilterSet from utilities.filters import TreeNodeMultipleChoiceFilter -from utilities.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * from .models import * diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 62f59c352..b04c14ba9 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -3,15 +3,15 @@ from django.contrib.auth.models import User from extras.filters import TagFilter from extras.filtersets import LocalConfigContextFilterSet +from netbox.filtersets import ( + BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet, +) from tenancy.filtersets import TenancyFilterSet from tenancy.models import Tenant from utilities.choices import ColorChoices from utilities.filters import ( MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, TreeNodeMultipleChoiceFilter, ) -from utilities.filtersets import ( - BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet, -) from virtualization.models import Cluster from .choices import * from .constants import * diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index 1451a34c0..84522c0ad 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -4,9 +4,9 @@ from django.contrib.contenttypes.models import ContentType from django.db.models import Q from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup +from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet from tenancy.models import Tenant, TenantGroup from utilities.filters import ContentTypeFilter -from utilities.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet from virtualization.models import Cluster, ClusterGroup from .choices import * from .models import * diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index a4c6d0415..5ab4994ea 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -7,11 +7,11 @@ from netaddr.core import AddrFormatError from dcim.models import Device, Interface, Region, Site, SiteGroup from extras.filters import TagFilter +from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from tenancy.filtersets import TenancyFilterSet from utilities.filters import ( ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter, ) -from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from virtualization.models import VirtualMachine, VMInterface from .choices import * from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF diff --git a/netbox/utilities/filtersets.py b/netbox/netbox/filtersets.py similarity index 99% rename from netbox/utilities/filtersets.py rename to netbox/netbox/filtersets.py index f738441dd..aa9e15385 100644 --- a/netbox/utilities/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -29,7 +29,7 @@ __all__ = ( class BaseFilterSet(django_filters.FilterSet): """ - A base filterset which provides common functionaly to all NetBox filtersets + A base FilterSet which provides common functionality to all NetBox FilterSets """ FILTER_DEFAULTS = deepcopy(django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS) FILTER_DEFAULTS.update({ diff --git a/netbox/secrets/filtersets.py b/netbox/secrets/filtersets.py index 1149fbd9b..644864ecb 100644 --- a/netbox/secrets/filtersets.py +++ b/netbox/secrets/filtersets.py @@ -3,7 +3,7 @@ from django.db.models import Q from dcim.models import Device from extras.filters import TagFilter -from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet +from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from virtualization.models import VirtualMachine from .models import Secret, SecretRole diff --git a/netbox/tenancy/filtersets.py b/netbox/tenancy/filtersets.py index 6a428f4b6..d00b78629 100644 --- a/netbox/tenancy/filtersets.py +++ b/netbox/tenancy/filtersets.py @@ -2,8 +2,8 @@ import django_filters from django.db.models import Q from extras.filters import TagFilter +from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from utilities.filters import TreeNodeMultipleChoiceFilter -from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from .models import Tenant, TenantGroup diff --git a/netbox/users/filtersets.py b/netbox/users/filtersets.py index 42f97bedc..6625cba36 100644 --- a/netbox/users/filtersets.py +++ b/netbox/users/filtersets.py @@ -2,8 +2,8 @@ import django_filters from django.contrib.auth.models import Group, User from django.db.models import Q +from netbox.filtersets import BaseFilterSet from users.models import ObjectPermission -from utilities.filtersets import BaseFilterSet __all__ = ( 'GroupFilterSet', diff --git a/netbox/utilities/tests/test_filters.py b/netbox/utilities/tests/test_filters.py index 6be611885..374167f1c 100644 --- a/netbox/utilities/tests/test_filters.py +++ b/netbox/utilities/tests/test_filters.py @@ -13,11 +13,11 @@ from dcim.models import ( ) from extras.filters import TagFilter from extras.models import TaggedItem +from netbox.filtersets import BaseFilterSet from utilities.filters import ( MACAddressFilter, MultiValueCharFilter, MultiValueDateFilter, MultiValueDateTimeFilter, MultiValueNumberFilter, MultiValueTimeFilter, TreeNodeMultipleChoiceFilter, ) -from utilities.filtersets import BaseFilterSet class TreeNodeMultipleChoiceFilterTest(TestCase): diff --git a/netbox/virtualization/filtersets.py b/netbox/virtualization/filtersets.py index 023dfb13b..6d930b69e 100644 --- a/netbox/virtualization/filtersets.py +++ b/netbox/virtualization/filtersets.py @@ -4,9 +4,9 @@ from django.db.models import Q from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup from extras.filters import TagFilter from extras.filtersets import LocalConfigContextFilterSet +from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from tenancy.filtersets import TenancyFilterSet from utilities.filters import MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter -from utilities.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet from .choices import * from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface