如何有效地在 django 中递归查询?
Posted
技术标签:
【中文标题】如何有效地在 django 中递归查询?【英文标题】:How to recursively query in django efficiently? 【发布时间】:2017-01-23 12:46:12 【问题描述】:我有一个模型,看起来像:
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)向 Admin 报告,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()
但很明显,这会导致大量的数据库调用,我的 API 最终会超时。有什么方法可以更有效地获取团队的所有成员?
【问题讨论】:
向我们展示您的 get_team() 方法 已添加到Q中。 您是否尝试过在外键上使用 _set 方法?我从来没有在递归模型上做过,所以不知道输出可能是什么样子。您也可以尝试 .select_related() 并查看最终结果。我认为这将为您提供必要的输出,但我不确定效率如何。 您应该使用一种有效的方式来存储/查询这些数据,例如github.com/django-mptt/django-mptt 【参考方案1】:如果您使用的数据库支持递归公用表表达式(例如 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 DjangoRecursive Common Table Expressions in PostgreSQL
【讨论】:
【参考方案2】:我找到了解决问题的方法。递归解决方案采用节点,进入它的第一个子节点并深入到层次结构的底部。然后再次回到第二个孩子(如果存在),然后再次下降到底部。简而言之,它会一一探索所有节点并将所有成员附加到一个数组中。我想出的解决方案是逐层获取成员。
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 调用数是我们想要找出其团队的成员下方存在的层数(层次结构)。
【讨论】:
您可以通过编写一个简单的递归查询来让数据库完成所有工作,如 Andrea 的回答所示。在您的情况下,您发出多个查询并将它们的结果附加在一起 - 不错,但是当有一个纯基于数据库的解决方案时,为什么让它如此脆弱? :-)以上是关于如何有效地在 django 中递归查询?的主要内容,如果未能解决你的问题,请参考以下文章