diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 4823549fd..8bdfb1578 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -43,6 +43,7 @@ * [#12415](https://github.com/netbox-community/netbox/issues/12415) - Fix `ImportError` exception when running RQ worker * [#12433](https://github.com/netbox-community/netbox/issues/12433) - Correct the application of URL query parameters for object list dashboard widgets * [#12436](https://github.com/netbox-community/netbox/issues/12436) - Remove extraneous "add" button from contact assignments list +* [#12463](https://github.com/netbox-community/netbox/issues/12463) - Fix the association of completed jobs with reports & scripts in the REST API * [#12464](https://github.com/netbox-community/netbox/issues/12464) - Apply credentials for git data source only when connecting via HTTP/S * [#12476](https://github.com/netbox-community/netbox/issues/12476) - Fix `TypeError` exception when running the `runscript` management command * [#12483](https://github.com/netbox-community/netbox/issues/12483) - Fix git remote data syncing when with HTTP proxies defined diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index e784be8e8..fccaa72f0 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -1219,28 +1219,6 @@ class DeviceComponentFilterSet(django_filters.FilterSet): to_field_name='name', label=_('Device (name)'), ) - device_type_id = django_filters.ModelMultipleChoiceFilter( - field_name='device__device_type', - queryset=DeviceType.objects.all(), - label=_('Device type (ID)'), - ) - device_type = django_filters.ModelMultipleChoiceFilter( - field_name='device__device_type__model', - queryset=DeviceType.objects.all(), - to_field_name='model', - label=_('Device type (model)'), - ) - device_role_id = django_filters.ModelMultipleChoiceFilter( - field_name='device__device_role', - queryset=DeviceRole.objects.all(), - label=_('Device role (ID)'), - ) - device_role = django_filters.ModelMultipleChoiceFilter( - field_name='device__device_role__slug', - queryset=DeviceRole.objects.all(), - to_field_name='slug', - label=_('Device role (slug)'), - ) virtual_chassis_id = django_filters.ModelMultipleChoiceFilter( field_name='device__virtual_chassis', queryset=VirtualChassis.objects.all(), diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index f10f08910..d31bba030 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -102,25 +102,13 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm): required=False, label=_('Virtual Chassis') ) - device_type_id = DynamicModelMultipleChoiceField( - queryset=DeviceType.objects.all(), - required=False, - label=_('Device type') - ) - device_role_id = DynamicModelMultipleChoiceField( - queryset=DeviceRole.objects.all(), - required=False, - label=_('Device role') - ) device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, query_params={ 'site_id': '$site_id', 'location_id': '$location_id', - 'virtual_chassis_id': '$virtual_chassis_id', - 'device_type_id': '$device_type_id', - 'role_id': '$device_role_id' + 'virtual_chassis_id': '$virtual_chassis_id' }, label=_('Device') ) @@ -1082,8 +1070,7 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'speed')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1102,8 +1089,7 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'speed')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1122,8 +1108,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1138,8 +1123,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1157,8 +1141,8 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): ('Addressing', ('vrf_id', 'l2vpn_id', 'mac_address', 'wwn')), ('PoE', ('poe_mode', 'poe_type')), ('Wireless', ('rf_role', 'rf_channel', 'rf_channel_width', 'tx_power')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id', 'vdc_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', + 'device_id', 'vdc_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) vdc_id = DynamicModelMultipleChoiceField( @@ -1258,8 +1242,7 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'color')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ('Cable', ('cabled', 'occupied')), ) model = FrontPort @@ -1278,8 +1261,7 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'color')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ('Cable', ('cabled', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1297,8 +1279,7 @@ class ModuleBayFilterForm(DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'position')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ) tag = TagFilterField(model) position = forms.CharField( @@ -1311,8 +1292,7 @@ class DeviceBayFilterForm(DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ) tag = TagFilterField(model) @@ -1322,8 +1302,7 @@ class InventoryItemFilterForm(DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id')), - ('Device', ('device_type_id', 'device_role_id', 'device_id')), + ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), ) role_id = DynamicModelMultipleChoiceField( queryset=InventoryItemRole.objects.all(), diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index f302024b0..3f796d7f8 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -187,11 +187,10 @@ class ReportViewSet(ViewSet): """ Compile all reports and their related results (if any). Result data is deferred in the list view. """ - report_content_type = ContentType.objects.get(app_label='extras', model='report') results = { - r.name: r - for r in Job.objects.filter( - object_type=report_content_type, + job.name: job + for job in Job.objects.filter( + object_type=ContentType.objects.get(app_label='extras', model='reportmodule'), status__in=JobStatusChoices.TERMINAL_STATE_CHOICES ).order_by('name', '-created').distinct('name').defer('data') } @@ -202,7 +201,7 @@ class ReportViewSet(ViewSet): # Attach Job objects to each report (if any) for report in report_list: - report.result = results.get(report.full_name, None) + report.result = results.get(report.name, None) serializer = serializers.ReportSerializer(report_list, many=True, context={ 'request': request, @@ -290,12 +289,10 @@ class ScriptViewSet(ViewSet): return module, script def list(self, request): - - script_content_type = ContentType.objects.get(app_label='extras', model='script') results = { - r.name: r - for r in Job.objects.filter( - object_type=script_content_type, + job.name: job + for job in Job.objects.filter( + object_type=ContentType.objects.get(app_label='extras', model='scriptmodule'), status__in=JobStatusChoices.TERMINAL_STATE_CHOICES ).order_by('name', '-created').distinct('name').defer('data') } @@ -306,7 +303,7 @@ class ScriptViewSet(ViewSet): # Attach Job objects to each script (if any) for script in script_list: - script.result = results.get(script.full_name, None) + script.result = results.get(script.name, None) serializer = serializers.ScriptSerializer(script_list, many=True, context={'request': request})