Я также собираюсь написать в QuerySet, так как это позволит вам связать их в цепочку.
И я предоставлю ответ как для поиска всех детей и всех родителей.
class PersonQuerySet(QuerySet):
def descendants(self, person):
q = Q(pk=person.pk)
for child in person.children.all():
q |= Q(pk__in=self.descendants(child))
return self.filter(q)
def ancestors(self, person):
q = Q(pk=person.pk)
if person.parent:
q |= Q(pk__in=self.ancestors(person.parent))
return self.filter(q)
Теперь нам нужно установить PersonQuerySet
в качестве менеджера.
class Person(TimeStampedModel):
name = models.CharField(max_length=32)
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
people = PersonQuerySet.as_manager()
Итак, вот последний запрос.
albert_einstein = Person.people.get(name='Albert Einstein')
bernhard_einstein = Person.peole.get(name='Bernhard Caesar Einstein')
einstein_folks = Person.people.descendants(albert_einstein).ancestors(bernhard_einstein)
Примечание:
Следующие решения так же медленны, как и остальные ответы ранее. Я проверял попадание в базу данных каждый раз, когда она рекурсирует своему ребенку / родителю. (Если кто-то может улучшить дальнейшее с некоторой оптимизацией и кэшированием, это будет лучше, возможно, предварительная выборка соответствующих данных перед запросом) Тем временем, mptt более практичен.