Skip to content

Commit 8a34e01

Browse files
committed
Make circular reference detection aware of parent type to avoid false-positives when multiple fields pointing to the same COT are present
1 parent ff32497 commit 8a34e01

File tree

1 file changed

+9
-8
lines changed

1 file changed

+9
-8
lines changed

netbox_custom_objects/models.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,8 +1041,8 @@ def _check_recursion(self):
10411041
return # Not a custom object type, no recursion possible
10421042

10431043
# Check for circular references by traversing the dependency chain
1044-
visited = {self.custom_object_type.id}
1045-
if self._has_circular_reference(related_custom_object_type, visited):
1044+
visited = {(self.custom_object_type.id, None)}
1045+
if self._has_circular_reference(related_custom_object_type, self.custom_object_type, visited):
10461046
raise ValidationError(
10471047
{
10481048
"related_object_type": _(
@@ -1052,7 +1052,7 @@ def _check_recursion(self):
10521052
}
10531053
)
10541054

1055-
def _has_circular_reference(self, custom_object_type, visited):
1055+
def _has_circular_reference(self, custom_object_type, parent_custom_object_type, visited):
10561056
"""
10571057
Recursively check if there's a circular reference by following the dependency chain.
10581058
@@ -1063,12 +1063,13 @@ def _has_circular_reference(self, custom_object_type, visited):
10631063
Returns:
10641064
bool: True if a circular reference is detected, False otherwise
10651065
"""
1066-
# If we've already visited this type, we have a cycle
1067-
if custom_object_type.id in visited:
1068-
return True
1066+
# If we've already visited this type (and it's from a different parent), we have a cycle
1067+
for visited_type_id, visited_parent_id in visited:
1068+
if visited_type_id == custom_object_type.id and visited_parent_id != parent_custom_object_type.id:
1069+
return True
10691070

10701071
# Add this type to visited set
1071-
visited.add(custom_object_type.id)
1072+
visited.add((custom_object_type.id, parent_custom_object_type.id))
10721073

10731074
# Check all object and multiobject fields in this custom object type
10741075
for field in custom_object_type.fields.filter(
@@ -1087,7 +1088,7 @@ def _has_circular_reference(self, custom_object_type, visited):
10871088
continue
10881089

10891090
# Recursively check this dependency
1090-
if self._has_circular_reference(next_custom_object_type, visited):
1091+
if self._has_circular_reference(next_custom_object_type, custom_object_type, visited):
10911092
return True
10921093

10931094
return False

0 commit comments

Comments
 (0)