如何有效地递归查询django?

时间:2016-09-15 13:14:08

标签: python django recursion list-comprehension django-orm

我有一个模型,看起来像:

class StaffMember(models.Model):

    id = models.OneToOneField(to=User, unique=True, primary_key=True, related_name='staff_member')
    supervisor = models.ForeignKey(to='self', null=True, blank=True, related_name='team_members')

我当前的团队层次结构的设计方式是让我们说一个管理员(谁是最重要的层次结构)。现在,让我们说3个人(A,B,C)向管理员报告,A,B和C中的每个人都有他们自己的团队向他们报告,等等。

对于任何员工,我想找到所有团队成员(沸腾到最底层次的层次结构)。 我目前获得一个人所有团队成员的方法就像:

def get_team(self):
    team = [self]
    for c in self.team_members.all():
        team += list(c.get_team())
        if len(team) > 2000:
            break
    return team

我通过以下方式获得会员的团队成员:

member = StaffMember.objects.get(pk=72)
team = member.get_team()

但显然,这导致了很多db调用,我的API最终会超时。什么可以更有效的方式来获取团队的所有成员?

2 个答案:

答案 0 :(得分:9)

如果您正在使用支持递归公用表表达式的数据库(例如PostgreSQL),那么这正是用例。

team = StaffMember.objects.raw('''
    WITH RECURSIVE team(id, supervisor) AS (
          SELECT id, supervisor 
          FROM staff_member
          WHERE id = 42
        UNION ALL
          SELECT sm.id, sm.supervisor
          FROM staff_member AS sm, team AS t
          WHERE sm.id = t.supervisor
        )
    SELECT * FROM team
''')

参考文献: Raw SQL queries in Django
Recursive Common Table Expressions in PostgreSQL

答案 1 :(得分:1)

我找到了问题的解决方案。递归解决方案接受节点,转到它的第一个子节点并深入到层次结构的底部。然后再次回到第二个孩子(如果存在),然后再次下降到底部。简而言之,它逐个探索所有节点并将所有成员附加到数组中。我提出的解决方案,逐层提取成员。

member = StaffMember.objects.get(id__id=user_id)

new_list = [member]

new_list = get_final_team(new_list)

def get_final_team(qs):
    team = []
    staffmembers = StaffMember.objects.filter(supervisor__in=qs)

    team += staffmembers 
    if staffmembers:
        interim_team_qs = get_final_team(staffmembers)
        for qs in interim_team_qs:
            team.append(qs)
    else:
        team = [qs]

    return team

此方法所需的db调用数是在我们想要找到的团队成员下面的层数(层次结构)。