当 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:未测试。测试一下再回来:)
我有一个模型 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:未测试。测试一下再回来:)