diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 6203e86a6..fb8e3aa92 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -94,6 +94,10 @@ class NodeAddChildrenApi(generics.UpdateAPIView): node_ids = request.data.get("nodes") children = Node.objects.filter(id__in=node_ids) for node in children: + if node.is_ancestor(instance): + # 如果 node 是 instance 的祖先节点,则不能添加为 instance 的子节点,否则会形成环,出现断层 + error = _("Node {} is an ancestor of node {}, can't be added as its child".format(node.value, instance.value)) + return Response(data={'error': error}, status=status.HTTP_400_BAD_REQUEST) node.parent = instance update_nodes_assets_amount.delay(ttl=5, node_ids=(instance.id,)) return Response("OK") diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index f2475cdc1..9ecdac54e 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -94,6 +94,10 @@ class FamilyMixin: def is_children(self, other): children_pattern = other.get_children_key_pattern(with_self=False) return re.match(children_pattern, self.key) + + def is_descendant(self, other): + all_children_pattern = other.get_all_children_pattern(with_self=False) + return re.match(all_children_pattern, self.key) def get_children(self, with_self=False): q = Q(parent_key=self.key) @@ -204,6 +208,9 @@ class FamilyMixin: def is_parent(self, other): return other.is_children(self) + def is_ancestor(self, other): + return other.is_descendant(self) + @property def parent(self): if self.is_org_root():