@@ -79,9 +79,12 @@ def ordered_queryset_from_pks(self, pks):
79
79
80
80
def add_child (self , child , ** kwargs ):
81
81
kwargs .update ({"parent" : self , "child" : child })
82
- disable_check = kwargs .pop ("disable_circular_check" , False )
82
+
83
+ disable_circular_check = kwargs .pop ("disable_circular_check" , False )
84
+ allow_duplicate_edges = kwargs .pop ("allow_duplicate_edges" , True )
85
+
83
86
cls = self .children .through (** kwargs )
84
- return cls .save (disable_circular_check = disable_check )
87
+ return cls .save (disable_circular_check = disable_circular_check , allow_duplicate_edges = allow_duplicate_edges )
85
88
86
89
def remove_child (self , child , delete_node = False ):
87
90
"""Removes the edge connecting this node to child, and optionally deletes the child node as well"""
@@ -379,6 +382,11 @@ def circular_checker(parent, child):
379
382
if child in parent .self_and_ancestors ():
380
383
raise ValidationError ("The object is an ancestor." )
381
384
385
+ @staticmethod
386
+ def duplicate_edge_checker (parent , child ):
387
+ if child in parent .self_and_descendants ():
388
+ raise ValidationError ("The edge is a duplicate." )
389
+
382
390
return Node
383
391
384
392
@@ -475,6 +483,10 @@ class Meta:
475
483
def save (self , * args , ** kwargs ):
476
484
if not kwargs .pop ("disable_circular_check" , False ):
477
485
self .parent .__class__ .circular_checker (self .parent , self .child )
486
+
487
+ if not kwargs .pop ("allow_duplicate_edges" , True ):
488
+ self .parent .__class__ .duplicate_edge_checker (self .parent , self .child )
489
+
478
490
super ().save (* args , ** kwargs )
479
491
480
492
return Edge
0 commit comments