# Buggy code
def clean(self):
    # Validate that termination A exists
    if not hasattr(self, "termination_a_type"):
        raise ValidationError("Termination A type has not been specified")
    try:
        self.termination_a_type.model_class().objects.get(pk=self.termination_a_id)
    except ObjectDoesNotExist:
        raise ValidationError(
            {"termination_a": "Invalid ID for type {}".format(self.termination_a_type)}
        )

    # Validate that termination B exists
    if not hasattr(self, "termination_b_type"):
        raise ValidationError("Termination B type has not been specified")
    try:
        self.termination_b_type.model_class().objects.get(pk=self.termination_b_id)
    except ObjectDoesNotExist:
        raise ValidationError(
            {"termination_b": "Invalid ID for type {}".format(self.termination_b_type)}
        )

    # If editing an existing Cable instance, check that neither termination has been modified.
    if self.pk:
        err_msg = "Cable termination points may not be modified. Delete and recreate the cable instead."
        if (
            self.termination_a_type != self._orig_termination_a_type
            or self.termination_a_id != self._orig_termination_a_id
        ):
            raise ValidationError({"termination_a": err_msg})
        if (
            self.termination_b_type != self._orig_termination_b_type
            or self.termination_b_id != self._orig_termination_b_id
        ):
            raise ValidationError({"termination_b": err_msg})

    type_a = self.termination_a_type.model
    type_b = self.termination_b_type.model

    # Validate interface types
    if type_a == "interface" and self.termination_a.type in NONCONNECTABLE_IFACE_TYPES:
        raise ValidationError(
            {
                "termination_a_id": "Cables cannot be terminated to {} interfaces".format(
                    self.termination_a.get_type_display()
                )
            }
        )
    if type_b == "interface" and self.termination_b.type in NONCONNECTABLE_IFACE_TYPES:
        raise ValidationError(
            {
                "termination_b_id": "Cables cannot be terminated to {} interfaces".format(
                    self.termination_b.get_type_display()
                )
            }
        )

    # Check that termination types are compatible
    if type_b not in COMPATIBLE_TERMINATION_TYPES.get(type_a):
        raise ValidationError(
            "Incompatible termination types: {} and {}".format(
                self.termination_a_type, self.termination_b_type
            )
        )

    # A RearPort with multiple positions must be connected to a component with an equal number of positions
    if isinstance(self.termination_a, RearPort) and isinstance(
        self.termination_b, RearPort
    ):
        if self.termination_a.positions != self.termination_b.positions:
            raise ValidationError(
                "{} has {} positions and {} has {}. Both terminations must have the same number of positions.".format(
                    self.termination_a,
                    self.termination_a.positions,
                    self.termination_b,
                    self.termination_b.positions,
                )
            )

    # A termination point cannot be connected to itself
    if self.termination_a == self.termination_b:
        raise ValidationError(
            "Cannot connect {} to itself".format(self.termination_a_type)
        )

    # A front port cannot be connected to its corresponding rear port
    if (
        type_a in ["frontport", "rearport"]
        and type_b in ["frontport", "rearport"]
        and (
            getattr(self.termination_a, "rear_port", None) == self.termination_b
            or getattr(self.termination_b, "rear_port", None) == self.termination_a
        )
    ):
        raise ValidationError(
            "A front port cannot be connected to it corresponding rear port"
        )

    # Check for an existing Cable connected to either termination object
    if self.termination_a.cable not in (None, self):
        raise ValidationError(
            "{} already has a cable attached (#{})".format(
                self.termination_a, self.termination_a.cable_id
            )
        )
    if self.termination_b.cable not in (None, self):
        raise ValidationError(
            "{} already has a cable attached (#{})".format(
                self.termination_b, self.termination_b.cable_id
            )
        )

    # Validate length and length_unit
    if self.length is not None and not self.length_unit:
        raise ValidationError("Must specify a unit when setting a cable length")
    elif self.length is None:
        self.length_unit = ""


# Traceback (IntegrityError)
Traceback (most recent call last):
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)

The above exception (duplicate key value violates unique constraint "dcim_interface__connected_interface_id_key"
DETAIL:  Key (_connected_interface_id)=(18403) already exists.
) was the direct cause of the following exception:
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/home/jstretch/netbox/netbox/dcim/views.py", line 2101, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 85, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/home/jstretch/netbox/netbox/dcim/views.py", line 2129, in post
obj = form.save()
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/forms/models.py", line 459, in save
self.instance.save()
File "/home/jstretch/netbox/netbox/dcim/models/__init__.py", line 2244, in save
super().save(*args, **kwargs)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/base.py", line 746, in save
force_update=force_update, update_fields=update_fields)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/base.py", line 795, in save_base
update_fields=update_fields, raw=raw, using=using,
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in send
for receiver in self._live_receivers(sender)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
for receiver in self._live_receivers(sender)
File "/home/jstretch/netbox/netbox/dcim/signals.py", line 70, in update_connected_endpoints
endpoint_a.save()
File "/home/jstretch/netbox/netbox/dcim/models/device_components.py", line 771, in save
return super().save(*args, **kwargs)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/base.py", line 746, in save
force_update=force_update, update_fields=update_fields)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/base.py", line 784, in save_base
force_update, using, update_fields,
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/base.py", line 865, in _save_table
forced_update)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/base.py", line 917, in _do_update
return filtered._update(values) > 0
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/query.py", line 771, in _update
return query.get_compiler(self.db).execute_sql(CURSOR)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1499, in execute_sql
cursor = super().execute_sql(result_type)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1151, in execute_sql
cursor.execute(sql, params)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/debug_toolbar/panels/sql/tracking.py", line 198, in execute
return self._record(self.cursor.execute, sql, params)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/debug_toolbar/panels/sql/tracking.py", line 133, in _record
return method(sql, params)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/cacheops/transaction.py", line 99, in execute
result = self._no_monkey.execute(self, sql, params)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/jstretch/.virtualenvs/netbox/lib/python3.6/site-packages/django/db/backends/utils.py", line 86, in _execute
return self.cursor.execute(sql, params)

Exception Type: IntegrityError at /dcim/front-ports/486/connect/interface/
Exception Value: duplicate key value violates unique constraint "dcim_interface__connected_interface_id_key"
DETAIL:  Key (_connected_interface_id)=(18403) already exists.

# Fixed code
def clean(self):
    # Validate that termination A exists
    if not hasattr(self, "termination_a_type"):
        raise ValidationError("Termination A type has not been specified")
    try:
        self.termination_a_type.model_class().objects.get(pk=self.termination_a_id)
    except ObjectDoesNotExist:
        raise ValidationError(
            {"termination_a": "Invalid ID for type {}".format(self.termination_a_type)}
        )

    # Validate that termination B exists
    if not hasattr(self, "termination_b_type"):
        raise ValidationError("Termination B type has not been specified")
    try:
        self.termination_b_type.model_class().objects.get(pk=self.termination_b_id)
    except ObjectDoesNotExist:
        raise ValidationError(
            {"termination_b": "Invalid ID for type {}".format(self.termination_b_type)}
        )

    # If editing an existing Cable instance, check that neither termination has been modified.
    if self.pk:
        err_msg = "Cable termination points may not be modified. Delete and recreate the cable instead."
        if (
            self.termination_a_type != self._orig_termination_a_type
            or self.termination_a_id != self._orig_termination_a_id
        ):
            raise ValidationError({"termination_a": err_msg})
        if (
            self.termination_b_type != self._orig_termination_b_type
            or self.termination_b_id != self._orig_termination_b_id
        ):
            raise ValidationError({"termination_b": err_msg})

    type_a = self.termination_a_type.model
    type_b = self.termination_b_type.model

    # Validate interface types
    if type_a == "interface" and self.termination_a.type in NONCONNECTABLE_IFACE_TYPES:
        raise ValidationError(
            {
                "termination_a_id": "Cables cannot be terminated to {} interfaces".format(
                    self.termination_a.get_type_display()
                )
            }
        )
    if type_b == "interface" and self.termination_b.type in NONCONNECTABLE_IFACE_TYPES:
        raise ValidationError(
            {
                "termination_b_id": "Cables cannot be terminated to {} interfaces".format(
                    self.termination_b.get_type_display()
                )
            }
        )

    # Check that termination types are compatible
    if type_b not in COMPATIBLE_TERMINATION_TYPES.get(type_a):
        raise ValidationError(
            f"Incompatible termination types: {self.termination_a_type} and {self.termination_b_type}"
        )

    # A RearPort with multiple positions must be connected to a RearPort with an equal number of positions
    for term_a, term_b in [
        (self.termination_a, self.termination_b),
        (self.termination_b, self.termination_a),
    ]:
        if isinstance(term_a, RearPort) and term_a.positions > 1:
            if not isinstance(term_b, RearPort):
                raise ValidationError(
                    "Rear ports with multiple positions may only be connected to other rear ports"
                )
            elif term_a.positions != term_b.positions:
                raise ValidationError(
                    f"{term_a} has {term_a.positions} position(s) but {term_b} has {term_b.positions}. "
                    f"Both terminations must have the same number of positions."
                )

    # A termination point cannot be connected to itself
    if self.termination_a == self.termination_b:
        raise ValidationError(f"Cannot connect {self.termination_a_type} to itself")

    # A front port cannot be connected to its corresponding rear port
    if (
        type_a in ["frontport", "rearport"]
        and type_b in ["frontport", "rearport"]
        and (
            getattr(self.termination_a, "rear_port", None) == self.termination_b
            or getattr(self.termination_b, "rear_port", None) == self.termination_a
        )
    ):
        raise ValidationError(
            "A front port cannot be connected to it corresponding rear port"
        )

    # Check for an existing Cable connected to either termination object
    if self.termination_a.cable not in (None, self):
        raise ValidationError(
            "{} already has a cable attached (#{})".format(
                self.termination_a, self.termination_a.cable_id
            )
        )
    if self.termination_b.cable not in (None, self):
        raise ValidationError(
            "{} already has a cable attached (#{})".format(
                self.termination_b, self.termination_b.cable_id
            )
        )

    # Validate length and length_unit
    if self.length is not None and not self.length_unit:
        raise ValidationError("Must specify a unit when setting a cable length")
    elif self.length is None:
        self.length_unit = ""