当 ForeignKey 不是 self-referencing 时,如何获取 Django object 的所有祖先?

How to get all ancestors of a Django object when ForeignKey is not self-referencing?

我有一个模型 Person 和另一个模型 Relation。 在创建新关系之前,我想检查一下这种关系是否可能。

这个 post 和其他一些类似的 posts 提供了一个解决方案,但是对于 self-referencing 模型,我的模型不是自引用的。 Django self-recursive 所有孩子的外键过滤查询

class Person(models.Model):
    identifier = IntegerField(null=True)
    title = CharField(max_length=100, null=True)

    def get_all_parent_ids(self):
        # I want to get all the ancestors of this person
        # but this method only gets immediate parents right now
        return [parent.parent.id for parent in self.parenting.all()]

    def get_all_children_ids(self):
        # I want to get all the descendants of this person
        # but this method only gets immediate children right now
        return [child.children.id for child in self.baby_sitting.all()]


class Relation(models.Model):
    name = CharField(max_length=50, null=True)
    parent = ForeignKey(Person, on_delete=models.PROTECT, related_name="parenting")
    children = ForeignKey(Person, on_delete=models.PROTECT, related_name="baby_sitting")

    class Meta:
        unique_together = ('parent', 'children')

def is_relation_possible(new_parent_id, new_children_id):
    new_parent_person = Person.objects.get(pk=new_parent_id)
    all_parents = new_parent_person.get_all_parent_ids()
    if new_children_id in all_parents:
        return False
    else:
        return True

例如:现有关系 - A 到 B - B 到 C - C 到 D - D 到 E

我想要 is_relation_possible(E, A) 到 return False,因为 E 有一个祖先 A.

目前它只检查立即parents而不是所有parents。

你应该使用递归:

def is_relation_possible(new_parent_id, new_children_id):
    new_parent_person = Person.objects.get(pk=new_parent_id)
    all_parents = new_parent_person.get_all_parent_ids()
    related = ( new_children_id in all_parents 
                or 
                any( is_relation_possible( ancestor_id, new_children_id) 
                     for ancestor_id in all_parents )  # (*1)
               )
    return related

(*1) 这里的诀窍是:如果自身相关 或者通过他们的祖先相关 .

则相关

注意 1:如果您使用的是图形而不是层次结构,它可能会进入无限循环。

注意2:未测试。测试一下再回来:)