diff --git a/netbox/circuits/models.py b/netbox/circuits/models.py index 26104d4d6..654207735 100644 --- a/netbox/circuits/models.py +++ b/netbox/circuits/models.py @@ -295,7 +295,7 @@ class CircuitTermination(ChangeLoggingMixin, BigIDModel, PathEndpoint, CableTerm return super().to_objectchange(action, related_object=circuit) @property - def parent(self): + def parent_object(self): return self.circuit def get_peer_termination(self): diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 68bf604ae..4a027b373 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -84,8 +84,8 @@ class ComponentModel(PrimaryModel): return super().to_objectchange(action, related_object=device) @property - def parent(self): - return getattr(self, 'device', None) + def parent_object(self): + return self.device class CableTermination(models.Model): @@ -152,6 +152,10 @@ class CableTermination(models.Model): def _occupied(self): return bool(self.mark_connected or self.cable_id) + @property + def parent_object(self): + raise NotImplementedError("CableTermination models must implement parent_object()") + class PathEndpoint(models.Model): """ @@ -207,7 +211,7 @@ class PathEndpoint(models.Model): # @extras_features('custom_fields', 'export_templates', 'webhooks') -class ConsolePort(CableTermination, PathEndpoint, ComponentModel): +class ConsolePort(ComponentModel, CableTermination, PathEndpoint): """ A physical console port within a Device. ConsolePorts connect to ConsoleServerPorts. """ @@ -251,7 +255,7 @@ class ConsolePort(CableTermination, PathEndpoint, ComponentModel): # @extras_features('custom_fields', 'export_templates', 'webhooks') -class ConsoleServerPort(CableTermination, PathEndpoint, ComponentModel): +class ConsoleServerPort(ComponentModel, CableTermination, PathEndpoint): """ A physical port within a Device (typically a designated console server) which provides access to ConsolePorts. """ @@ -295,7 +299,7 @@ class ConsoleServerPort(CableTermination, PathEndpoint, ComponentModel): # @extras_features('custom_fields', 'export_templates', 'webhooks') -class PowerPort(CableTermination, PathEndpoint, ComponentModel): +class PowerPort(ComponentModel, CableTermination, PathEndpoint): """ A physical power supply (intake) port within a Device. PowerPorts connect to PowerOutlets. """ @@ -407,7 +411,7 @@ class PowerPort(CableTermination, PathEndpoint, ComponentModel): # @extras_features('custom_fields', 'export_templates', 'webhooks') -class PowerOutlet(CableTermination, PathEndpoint, ComponentModel): +class PowerOutlet(ComponentModel, CableTermination, PathEndpoint): """ A physical power outlet (output) within a Device which provides power to a PowerPort. """ @@ -508,7 +512,7 @@ class BaseInterface(models.Model): @extras_features('custom_fields', 'export_templates', 'webhooks') -class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface): +class Interface(ComponentModel, BaseInterface, CableTermination, PathEndpoint): """ A network interface within a Device. A physical Interface can connect to exactly one other Interface. """ @@ -619,16 +623,12 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface): raise ValidationError({'lag': "A LAG interface cannot be its own parent."}) # Validate untagged VLAN - if self.untagged_vlan and self.untagged_vlan.site not in [self.parent.site, None]: + if self.untagged_vlan and self.untagged_vlan.site not in [self.device.site, None]: raise ValidationError({ 'untagged_vlan': "The untagged VLAN ({}) must belong to the same site as the interface's parent " "device, or it must be global".format(self.untagged_vlan) }) - @property - def parent(self): - return self.device - @property def is_connectable(self): return self.type not in NONCONNECTABLE_IFACE_TYPES @@ -655,7 +655,7 @@ class Interface(CableTermination, PathEndpoint, ComponentModel, BaseInterface): # @extras_features('custom_fields', 'export_templates', 'webhooks') -class FrontPort(CableTermination, ComponentModel): +class FrontPort(ComponentModel, CableTermination): """ A pass-through port on the front of a Device. """ @@ -721,7 +721,7 @@ class FrontPort(CableTermination, ComponentModel): @extras_features('custom_fields', 'export_templates', 'webhooks') -class RearPort(CableTermination, ComponentModel): +class RearPort(ComponentModel, CableTermination): """ A pass-through port on the rear of a Device. """ diff --git a/netbox/dcim/models/power.py b/netbox/dcim/models/power.py index b7b351f37..db98f2fba 100644 --- a/netbox/dcim/models/power.py +++ b/netbox/dcim/models/power.py @@ -201,7 +201,7 @@ class PowerFeed(PrimaryModel, PathEndpoint, CableTermination): super().save(*args, **kwargs) @property - def parent(self): + def parent_object(self): return self.power_panel def get_type_class(self): diff --git a/netbox/dcim/tables/template_code.py b/netbox/dcim/tables/template_code.py index f634cf426..7449bb9c8 100644 --- a/netbox/dcim/tables/template_code.py +++ b/netbox/dcim/tables/template_code.py @@ -1,6 +1,6 @@ CABLETERMINATION = """ {% if value %} - {{ value.parent }} + {{ value.parent_object }} {{ value }} {% else %} @@ -64,7 +64,7 @@ POWERFEED_CABLE = """ """ POWERFEED_CABLETERMINATION = """ -{{ value.parent }} +{{ value.parent_object }} {{ value }} """ diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 4c76e16a6..f39391a8b 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2178,13 +2178,13 @@ class CableCreateView(generic.ObjectEditView): initial_data = {k: request.GET[k] for k in request.GET} # Set initial site and rack based on side A termination (if not already set) - termination_a_site = getattr(obj.termination_a.parent, 'site', None) + termination_a_site = getattr(obj.termination_a.parent_object, 'site', None) if termination_a_site and 'termination_b_region' not in initial_data: initial_data['termination_b_region'] = termination_a_site.region if 'termination_b_site' not in initial_data: initial_data['termination_b_site'] = termination_a_site if 'termination_b_rack' not in initial_data: - initial_data['termination_b_rack'] = getattr(obj.termination_a.parent, 'rack', None) + initial_data['termination_b_rack'] = getattr(obj.termination_a.parent_object, 'rack', None) form = self.model_form(instance=obj, initial=initial_data) diff --git a/netbox/templates/dcim/cable_trace.html b/netbox/templates/dcim/cable_trace.html index a39ada1ce..1a8667787 100644 --- a/netbox/templates/dcim/cable_trace.html +++ b/netbox/templates/dcim/cable_trace.html @@ -102,12 +102,12 @@ - {{ cablepath.origin.parent }} / {{ cablepath.origin }} + {{ cablepath.origin.parent_object }} / {{ cablepath.origin }} {% if cablepath.destination %} - {{ cablepath.destination }} ({{ cablepath.destination.parent }}) + {{ cablepath.destination }} ({{ cablepath.destination.parent_object }}) {% else %} Incomplete {% endif %} diff --git a/netbox/templates/dcim/inc/cabletermination.html b/netbox/templates/dcim/inc/cabletermination.html index 1962248e7..26a7e1cd3 100644 --- a/netbox/templates/dcim/inc/cabletermination.html +++ b/netbox/templates/dcim/inc/cabletermination.html @@ -1,12 +1,12 @@ - {% if termination.parent.provider %} + {% if termination.parent_object.provider %} - - {{ termination.parent.provider }} - {{ termination.parent }} + + {{ termination.parent_object.provider }} + {{ termination.parent_object }} {% else %} - {{ termination.parent }} + {{ termination.parent_object }} {% endif %} diff --git a/netbox/templates/dcim/inc/endpoint_connection.html b/netbox/templates/dcim/inc/endpoint_connection.html index 3169d2ffc..d5b9f6112 100644 --- a/netbox/templates/dcim/inc/endpoint_connection.html +++ b/netbox/templates/dcim/inc/endpoint_connection.html @@ -1,6 +1,6 @@ {% if path.destination_id %} {% with endpoint=path.destination %} - {{ endpoint.parent }} + {{ endpoint.parent_object }} {{ endpoint }} {% endwith %} {% else %}