From 58659cf3b6ff6939520f0b6045137d96f27fc515 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 27 Apr 2021 10:04:28 -0400 Subject: [PATCH] Fixes #6262: Support filtering by created/updated time for all relevant objects --- docs/release-notes/version-2.11.md | 1 + netbox/circuits/filters.py | 6 ++-- netbox/dcim/filters.py | 26 ++++++++-------- netbox/extras/filters.py | 48 +++++++++++++++--------------- netbox/ipam/filters.py | 6 ++-- netbox/secrets/filters.py | 2 +- netbox/tenancy/filters.py | 2 +- netbox/virtualization/filters.py | 4 +-- 8 files changed, 48 insertions(+), 47 deletions(-) diff --git a/docs/release-notes/version-2.11.md b/docs/release-notes/version-2.11.md index 33de756e9..84dffa1e3 100644 --- a/docs/release-notes/version-2.11.md +++ b/docs/release-notes/version-2.11.md @@ -16,6 +16,7 @@ * [#6252](https://github.com/netbox-community/netbox/issues/6252) - Fix assignment of console port speed values above 19.2kbps * [#6254](https://github.com/netbox-community/netbox/issues/6254) - Disable ordering of space column in racks table * [#6258](https://github.com/netbox-community/netbox/issues/6258) - Fix parent assignment for SiteGroup API serializer +* [#6262](https://github.com/netbox-community/netbox/issues/6262) - Support filtering by created/updated time for all relevant objects * [#6267](https://github.com/netbox-community/netbox/issues/6267) - Fix cable tracing API endpoint for circuit terminations * [#6289](https://github.com/netbox-community/netbox/issues/6289) - Fix assignment of VC member interfaces to LAG interfaces diff --git a/netbox/circuits/filters.py b/netbox/circuits/filters.py index f5d81c7bd..034a99ac9 100644 --- a/netbox/circuits/filters.py +++ b/netbox/circuits/filters.py @@ -1,7 +1,7 @@ import django_filters from django.db.models import Q -from dcim.filters import CableTerminationFilterSet, PathEndpointFilterSet +from dcim.filters import CableTerminationFilterSet from dcim.models import Region, Site, SiteGroup from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from tenancy.filters import TenancyFilterSet @@ -110,7 +110,7 @@ class ProviderNetworkFilterSet(BaseFilterSet, CustomFieldModelFilterSet, Created ).distinct() -class CircuitTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class CircuitTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = CircuitType @@ -207,7 +207,7 @@ class CircuitFilterSet(BaseFilterSet, CustomFieldModelFilterSet, TenancyFilterSe ).distinct() -class CircuitTerminationFilterSet(BaseFilterSet, CableTerminationFilterSet): +class CircuitTerminationFilterSet(BaseFilterSet, CreatedUpdatedFilterSet, CableTerminationFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index dce0d38e2..29c4281ba 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -57,7 +57,7 @@ __all__ = ( ) -class RegionFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class RegionFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=Region.objects.all(), label='Parent region (ID)', @@ -74,7 +74,7 @@ class RegionFilterSet(BaseFilterSet, NameSlugSearchFilterSet): fields = ['id', 'name', 'slug', 'description'] -class SiteGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class SiteGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=SiteGroup.objects.all(), label='Parent site group (ID)', @@ -154,7 +154,7 @@ class SiteFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, return queryset.filter(qs_filter) -class LocationFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class LocationFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', @@ -218,7 +218,7 @@ class LocationFilterSet(BaseFilterSet, NameSlugSearchFilterSet): ) -class RackRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class RackRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = RackRole @@ -323,7 +323,7 @@ class RackFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, ) -class RackReservationFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet): +class RackReservationFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -383,7 +383,7 @@ class RackReservationFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModel ) -class ManufacturerFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class ManufacturerFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = Manufacturer @@ -476,7 +476,7 @@ class DeviceTypeFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdat return queryset.exclude(devicebaytemplates__isnull=value) -class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet): +class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet, CreatedUpdatedFilterSet): devicetype_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceType.objects.all(), field_name='device_type_id', @@ -556,14 +556,14 @@ class DeviceBayTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): fields = ['id', 'name'] -class DeviceRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class DeviceRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = DeviceRole fields = ['id', 'name', 'slug', 'color', 'vm_role'] -class PlatformFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class PlatformFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer', queryset=Manufacturer.objects.all(), @@ -792,7 +792,7 @@ class DeviceFilterSet( return queryset.exclude(devicebays__isnull=value) -class DeviceComponentFilterSet(CustomFieldModelFilterSet): +class DeviceComponentFilterSet(CustomFieldModelFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1129,7 +1129,7 @@ class InventoryItemFilterSet(BaseFilterSet, DeviceComponentFilterSet): return queryset.filter(qs_filter) -class VirtualChassisFilterSet(BaseFilterSet, CustomFieldModelFilterSet): +class VirtualChassisFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1209,7 +1209,7 @@ class VirtualChassisFilterSet(BaseFilterSet, CustomFieldModelFilterSet): return queryset.filter(qs_filter).distinct() -class CableFilterSet(BaseFilterSet, CustomFieldModelFilterSet): +class CableFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -1340,7 +1340,7 @@ class InterfaceConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): fields = [] -class PowerPanelFilterSet(BaseFilterSet): +class PowerPanelFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/extras/filters.py b/netbox/extras/filters.py index 4b5c42eeb..aacdbda6b 100644 --- a/netbox/extras/filters.py +++ b/netbox/extras/filters.py @@ -36,6 +36,27 @@ 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( @@ -119,7 +140,7 @@ class ImageAttachmentFilterSet(BaseFilterSet): fields = ['id', 'content_type_id', 'object_id', 'name'] -class JournalEntryFilterSet(BaseFilterSet): +class JournalEntryFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -150,7 +171,7 @@ class JournalEntryFilterSet(BaseFilterSet): return queryset.filter(comments__icontains=value) -class TagFilterSet(BaseFilterSet): +class TagFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -169,7 +190,7 @@ class TagFilterSet(BaseFilterSet): ) -class ConfigContextFilterSet(BaseFilterSet): +class ConfigContextFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -341,27 +362,6 @@ class ObjectChangeFilterSet(BaseFilterSet): ) -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' - ) - - # # Job Results # diff --git a/netbox/ipam/filters.py b/netbox/ipam/filters.py index cac3d0eea..8f4030411 100644 --- a/netbox/ipam/filters.py +++ b/netbox/ipam/filters.py @@ -116,7 +116,7 @@ class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilt fields = ['id', 'name'] -class RIRFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class RIRFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = RIR @@ -173,7 +173,7 @@ class AggregateFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilter return queryset.none() -class RoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class RoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): q = django_filters.CharFilter( method='search', label='Search', @@ -535,7 +535,7 @@ class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilter return queryset.exclude(assigned_object_id__isnull=value) -class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): scope_type = ContentTypeFilter() region = django_filters.NumberFilter( method='filter_scope' diff --git a/netbox/secrets/filters.py b/netbox/secrets/filters.py index 0cf4c2045..fb36c827a 100644 --- a/netbox/secrets/filters.py +++ b/netbox/secrets/filters.py @@ -14,7 +14,7 @@ __all__ = ( ) -class SecretRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class SecretRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = SecretRole diff --git a/netbox/tenancy/filters.py b/netbox/tenancy/filters.py index d61081de4..0581866a4 100644 --- a/netbox/tenancy/filters.py +++ b/netbox/tenancy/filters.py @@ -13,7 +13,7 @@ __all__ = ( ) -class TenantGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class TenantGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=TenantGroup.objects.all(), label='Tenant group (ID)', diff --git a/netbox/virtualization/filters.py b/netbox/virtualization/filters.py index d710bcbe2..6d706b6cf 100644 --- a/netbox/virtualization/filters.py +++ b/netbox/virtualization/filters.py @@ -20,14 +20,14 @@ __all__ = ( ) -class ClusterTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class ClusterTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = ClusterType fields = ['id', 'name', 'slug', 'description'] -class ClusterGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet): +class ClusterGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class Meta: model = ClusterGroup