Django自我递归外键过滤查询所有孩子

Ahs*_*san 24 django model recursive-query

我有这个模型与自引用外键关系:

class Person(TimeStampedModel):
    name = models.CharField(max_length=32)
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
Run Code Online (Sandbox Code Playgroud)

现在我想为一个人获得所有多层次的孩子.我该如何为它编写Django查询?它需要表现得像递归函数.

sun*_*nn0 31

您始终可以向模型添加递归函数:

编辑:根据SeomGi Han修正

def get_all_children(self, include_self=True):
    r = []
    if include_self:
        r.append(self)
    for c in Person.objects.filter(parent=self):
        _r = c.get_all_children(include_self=True)
        if 0 < len(_r):
            r.extend(_r)
    return r
Run Code Online (Sandbox Code Playgroud)

(如果你有很多递归或数据,请不要使用它...)

仍然按照errx的建议推荐mptt.


err*_*rrx 14

您应该阅读有关修改的预订树遍历的信息.这是django的实现. https://github.com/django-mptt/django-mptt/

  • @Ashan:你可以随时阅读它,例如:http://dev.mysql.com/tech-resources/articles/hierarchical-data.html并自己编写代码 (2认同)

小智 8

sunn0的建议很棒,但是get_all_children()会返回奇怪的结果.它返回类似[Person1,[Person3,Person4],[]]的内容.它应该改为如下.

def get_all_children(self, include_self=True):
    r = []
    if include_self:
        r.append(self)
    for c in Person.objects.filter(parent=self):
        _r = c.get_all_children(include_self=True)
        if 0 < len(_r):
            r.extend(_r)
    return r
Run Code Online (Sandbox Code Playgroud)


Tom*_*ski 5

如果您知道树的最大深度,可以尝试这样的(未经测试):

Person.objects.filter(Q(parent=my_person)|Q(parent__parent=my_person)| Q(parent__parent__parent=my_person))
Run Code Online (Sandbox Code Playgroud)