diff --git a/netbox/circuits/migrations/0022_drop_connected_endpoint.py b/netbox/circuits/migrations/0022_drop_connected_endpoint.py index 59647dd2bc..e5540b44d1 100644 --- a/netbox/circuits/migrations/0022_drop_connected_endpoint.py +++ b/netbox/circuits/migrations/0022_drop_connected_endpoint.py @@ -1,4 +1,4 @@ -# Generated by Django 3.1 on 2020-10-05 13:56 +# Generated by Django 3.1 on 2020-10-05 14:07 from django.db import migrations @@ -14,4 +14,8 @@ class Migration(migrations.Migration): model_name='circuittermination', name='connected_endpoint', ), + migrations.RemoveField( + model_name='circuittermination', + name='connection_status', + ), ] diff --git a/netbox/circuits/models.py b/netbox/circuits/models.py index 746a71b3cf..725fe4b3f8 100644 --- a/netbox/circuits/models.py +++ b/netbox/circuits/models.py @@ -2,7 +2,6 @@ from django.urls import reverse from taggit.managers import TaggableManager -from dcim.constants import CONNECTION_STATUS_CHOICES from dcim.fields import ASNField from dcim.models import CableTermination, PathEndpoint from extras.models import ChangeLoggedModel, CustomFieldModel, ObjectChange, TaggedItem @@ -248,11 +247,6 @@ class CircuitTermination(PathEndpoint, CableTermination): on_delete=models.PROTECT, related_name='circuit_terminations' ) - connection_status = models.BooleanField( - choices=CONNECTION_STATUS_CHOICES, - blank=True, - null=True - ) port_speed = models.PositiveIntegerField( verbose_name='Port speed (Kbps)' ) diff --git a/netbox/dcim/api/nested_serializers.py b/netbox/dcim/api/nested_serializers.py index 40b03ada6f..159540ece8 100644 --- a/netbox/dcim/api/nested_serializers.py +++ b/netbox/dcim/api/nested_serializers.py @@ -1,8 +1,7 @@ from rest_framework import serializers -from dcim.constants import CONNECTION_STATUS_CHOICES from dcim import models -from utilities.api import ChoiceField, WritableNestedSerializer +from utilities.api import WritableNestedSerializer __all__ = [ 'NestedCableSerializer', @@ -228,51 +227,46 @@ class Meta: class NestedConsoleServerPortSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail') device = NestedDeviceSerializer(read_only=True) - connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True) class Meta: model = models.ConsoleServerPort - fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status'] + fields = ['id', 'url', 'device', 'name', 'cable'] class NestedConsolePortSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail') device = NestedDeviceSerializer(read_only=True) - connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True) class Meta: model = models.ConsolePort - fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status'] + fields = ['id', 'url', 'device', 'name', 'cable'] class NestedPowerOutletSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail') device = NestedDeviceSerializer(read_only=True) - connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True) class Meta: model = models.PowerOutlet - fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status'] + fields = ['id', 'url', 'device', 'name', 'cable'] class NestedPowerPortSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail') device = NestedDeviceSerializer(read_only=True) - connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True) class Meta: model = models.PowerPort - fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status'] + fields = ['id', 'url', 'device', 'name', 'cable'] class NestedInterfaceSerializer(WritableNestedSerializer): device = NestedDeviceSerializer(read_only=True) url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail') - connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, read_only=True) class Meta: model = models.Interface - fields = ['id', 'url', 'device', 'name', 'cable', 'connection_status'] + fields = ['id', 'url', 'device', 'name', 'cable'] class NestedRearPortSerializer(WritableNestedSerializer): diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 0cf78fafc6..b591ae36a0 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -33,8 +33,8 @@ class ConnectedEndpointSerializer(ValidatedModelSerializer): connection_status = serializers.SerializerMethodField(read_only=True) def get_connected_endpoint_type(self, obj): - if obj.path is not None: - return f'{obj.connected_endpoint._meta.app_label}.{obj.connected_endpoint._meta.model_name}' + if obj._path is not None and obj._path.destination is not None: + return f'{obj._path.destination._meta.app_label}.{obj._path.destination._meta.model_name}' return None @swagger_serializer_method(serializer_or_field=serializers.DictField) @@ -42,17 +42,17 @@ def get_connected_endpoint(self, obj): """ Return the appropriate serializer for the type of connected object. """ - if obj.path is not None: - serializer = get_serializer_for_model(obj.connected_endpoint, prefix='Nested') + if obj._path is not None and obj._path.destination is not None: + serializer = get_serializer_for_model(obj._path.destination, prefix='Nested') context = {'request': self.context['request']} - return serializer(obj.path.destination, context=context).data + return serializer(obj._path.destination, context=context).data return None # TODO: Tweak the representation for this field @swagger_serializer_method(serializer_or_field=serializers.BooleanField) def get_connection_status(self, obj): - if obj.path is not None: - return obj.path.is_connected + if obj._path is not None: + return obj._path.is_connected return None @@ -716,7 +716,7 @@ class Meta: class InterfaceConnectionSerializer(ValidatedModelSerializer): interface_a = serializers.SerializerMethodField() interface_b = NestedInterfaceSerializer(source='connected_endpoint') - connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, required=False) + # connection_status = ChoiceField(choices=CONNECTION_STATUS_CHOICES, required=False) class Meta: model = Interface diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index aa5c62552c..d16f5d1aa4 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -760,11 +760,7 @@ class PathEndpointFilterSet(django_filters.FilterSet): ) def filter_is_connected(self, queryset, name, value): - kwargs = {'connected_paths': 1 if value else 0} - # TODO: Boolean rather than Count()? - return queryset.annotate( - connected_paths=Count('_paths', filter=Q(_paths__is_connected=True)) - ).filter(**kwargs) + return queryset.filter(_path__is_connected=True) class ConsolePortFilterSet(BaseFilterSet, DeviceComponentFilterSet, PathEndpointFilterSet): @@ -1169,7 +1165,7 @@ class ConsoleConnectionFilterSet(BaseFilterSet): class Meta: model = ConsolePort - fields = ['name', 'connection_status'] + fields = ['name'] # TODO: Fix filters # def filter_site(self, queryset, name, value): @@ -1201,7 +1197,7 @@ class PowerConnectionFilterSet(BaseFilterSet): class Meta: model = PowerPort - fields = ['name', 'connection_status'] + fields = ['name'] # TODO: Fix filters # def filter_site(self, queryset, name, value): @@ -1233,7 +1229,7 @@ class InterfaceConnectionFilterSet(BaseFilterSet): class Meta: model = Interface - fields = ['connection_status'] + fields = [] # TODO: Fix filters # def filter_site(self, queryset, name, value): diff --git a/netbox/dcim/migrations/0121_drop_connected_endpoint.py b/netbox/dcim/migrations/0121_drop_connected_endpoint.py index f05cfdd1a5..9404ecf53e 100644 --- a/netbox/dcim/migrations/0121_drop_connected_endpoint.py +++ b/netbox/dcim/migrations/0121_drop_connected_endpoint.py @@ -1,4 +1,4 @@ -# Generated by Django 3.1 on 2020-10-05 13:56 +# Generated by Django 3.1 on 2020-10-05 14:07 from django.db import migrations @@ -14,6 +14,14 @@ class Migration(migrations.Migration): model_name='consoleport', name='connected_endpoint', ), + migrations.RemoveField( + model_name='consoleport', + name='connection_status', + ), + migrations.RemoveField( + model_name='consoleserverport', + name='connection_status', + ), migrations.RemoveField( model_name='interface', name='_connected_circuittermination', @@ -22,10 +30,22 @@ class Migration(migrations.Migration): model_name='interface', name='_connected_interface', ), + migrations.RemoveField( + model_name='interface', + name='connection_status', + ), migrations.RemoveField( model_name='powerfeed', name='connected_endpoint', ), + migrations.RemoveField( + model_name='powerfeed', + name='connection_status', + ), + migrations.RemoveField( + model_name='poweroutlet', + name='connection_status', + ), migrations.RemoveField( model_name='powerport', name='_connected_powerfeed', @@ -34,4 +54,8 @@ class Migration(migrations.Migration): model_name='powerport', name='_connected_poweroutlet', ), + migrations.RemoveField( + model_name='powerport', + name='connection_status', + ), ] diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 72edfc46e2..863b39e626 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -175,11 +175,6 @@ class ConsolePort(CableTermination, PathEndpoint, ComponentModel): blank=True, help_text='Physical port type' ) - connection_status = models.BooleanField( - choices=CONNECTION_STATUS_CHOICES, - blank=True, - null=True - ) tags = TaggableManager(through=TaggedItem) csv_headers = ['device', 'name', 'label', 'type', 'description'] @@ -216,11 +211,6 @@ class ConsoleServerPort(CableTermination, PathEndpoint, ComponentModel): blank=True, help_text='Physical port type' ) - connection_status = models.BooleanField( - choices=CONNECTION_STATUS_CHOICES, - blank=True, - null=True - ) tags = TaggableManager(through=TaggedItem) csv_headers = ['device', 'name', 'label', 'type', 'description'] @@ -269,11 +259,6 @@ class PowerPort(CableTermination, PathEndpoint, ComponentModel): validators=[MinValueValidator(1)], help_text="Allocated power draw (watts)" ) - connection_status = models.BooleanField( - choices=CONNECTION_STATUS_CHOICES, - blank=True, - null=True - ) tags = TaggableManager(through=TaggedItem) csv_headers = ['device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description'] @@ -368,11 +353,6 @@ class PowerOutlet(CableTermination, PathEndpoint, ComponentModel): blank=True, help_text="Phase (for three-phase feeds)" ) - connection_status = models.BooleanField( - choices=CONNECTION_STATUS_CHOICES, - blank=True, - null=True - ) tags = TaggableManager(through=TaggedItem) csv_headers = ['device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description'] @@ -448,11 +428,6 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface): max_length=100, blank=True ) - connection_status = models.BooleanField( - choices=CONNECTION_STATUS_CHOICES, - blank=True, - null=True - ) lag = models.ForeignKey( to='self', on_delete=models.SET_NULL, diff --git a/netbox/dcim/models/power.py b/netbox/dcim/models/power.py index ec1480a7ef..f869a3af43 100644 --- a/netbox/dcim/models/power.py +++ b/netbox/dcim/models/power.py @@ -88,11 +88,6 @@ class PowerFeed(ChangeLoggedModel, PathEndpoint, CableTermination, CustomFieldMo blank=True, null=True ) - connection_status = models.BooleanField( - choices=CONNECTION_STATUS_CHOICES, - blank=True, - null=True - ) name = models.CharField( max_length=50 ) diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 528301f8f4..5c13b51229 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -977,7 +977,7 @@ def test_unique_name_per_site_constraint(self): class ConsolePortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = ConsolePort - brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + brief_fields = ['cable', 'device', 'id', 'name', 'url'] bulk_update_data = { 'description': 'New description', } @@ -1016,7 +1016,7 @@ def setUpTestData(cls): class ConsoleServerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = ConsoleServerPort - brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + brief_fields = ['cable', 'device', 'id', 'name', 'url'] bulk_update_data = { 'description': 'New description', } @@ -1055,7 +1055,7 @@ def setUpTestData(cls): class PowerPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = PowerPort - brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + brief_fields = ['cable', 'device', 'id', 'name', 'url'] bulk_update_data = { 'description': 'New description', } @@ -1094,7 +1094,7 @@ def setUpTestData(cls): class PowerOutletTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = PowerOutlet - brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + brief_fields = ['cable', 'device', 'id', 'name', 'url'] bulk_update_data = { 'description': 'New description', } @@ -1133,7 +1133,7 @@ def setUpTestData(cls): class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): model = Interface - brief_fields = ['cable', 'connection_status', 'device', 'id', 'name', 'url'] + brief_fields = ['cable', 'device', 'id', 'name', 'url'] bulk_update_data = { 'description': 'New description', } @@ -1189,7 +1189,7 @@ def setUpTestData(cls): ] -class FrontPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): +class FrontPortTest(APIViewTestCases.APIViewTestCase): model = FrontPort brief_fields = ['cable', 'device', 'id', 'name', 'url'] bulk_update_data = { @@ -1247,7 +1247,7 @@ def setUpTestData(cls): ] -class RearPortTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase): +class RearPortTest(APIViewTestCases.APIViewTestCase): model = RearPort brief_fields = ['cable', 'device', 'id', 'name', 'url'] bulk_update_data = { diff --git a/netbox/dcim/utils.py b/netbox/dcim/utils.py index 4ef902dc76..40896f97bb 100644 --- a/netbox/dcim/utils.py +++ b/netbox/dcim/utils.py @@ -26,7 +26,7 @@ def trace_path(node): position_stack = [] is_connected = True - if node.cable is None: + if node is None or node.cable is None: return [], None, False while node.cable is not None: diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 7a1028dece..9290a2b4af 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -1018,36 +1018,31 @@ def get(self, request, pk): # Console ports consoleports = ConsolePort.objects.restrict(request.user, 'view').filter(device=device).prefetch_related( - Prefetch('_paths', queryset=CablePath.objects.filter(destination_id__isnull=False)), - 'cable', + 'cable', '_path', ) # Console server ports consoleserverports = ConsoleServerPort.objects.restrict(request.user, 'view').filter( device=device ).prefetch_related( - Prefetch('_paths', queryset=CablePath.objects.filter(destination_id__isnull=False)), - 'cable', + 'cable', '_path', ) # Power ports powerports = PowerPort.objects.restrict(request.user, 'view').filter(device=device).prefetch_related( - Prefetch('_paths', queryset=CablePath.objects.filter(destination_id__isnull=False)), - 'cable', + 'cable', '_path', ) # Power outlets poweroutlets = PowerOutlet.objects.restrict(request.user, 'view').filter(device=device).prefetch_related( - Prefetch('_paths', queryset=CablePath.objects.filter(destination_id__isnull=False)), - 'cable', 'power_port', + 'cable', 'power_port', '_path', ) # Interfaces interfaces = device.vc_interfaces.restrict(request.user, 'view').prefetch_related( - Prefetch('_paths', queryset=CablePath.objects.filter(destination_id__isnull=False)), Prefetch('ip_addresses', queryset=IPAddress.objects.restrict(request.user)), Prefetch('member_interfaces', queryset=Interface.objects.restrict(request.user)), - 'lag', 'cable', 'tags', + 'lag', 'cable', '_path', 'tags', ) # Front ports