gpt4 book ai didi

django - 使用 Django Treebeard 获取祖先时如何防止 N+1 查询?

转载 作者:行者123 更新时间:2023-12-05 04:31:45 25 4
gpt4 key购买 nike

我们正在使用 Django Treebeard 的物化路径对组织层次结构进行建模,如下所示:

Organizational Hierarchy Example

现在组织树中的每个节点都可以有多个任务:

class Organization(MP_Node):
node_order_by = ['name']
name = models.CharField(max_length=100)

class Task(models.Model):
organization = models.ForeignKey(Organization, on_delete=models.CASCADE)
description= models.TextField()

给定任务列表,我们希望在结果中包含每个任务的完整组织路径。我们如何在不需要 N+1 查询的情况下实现这一点?

例如,组织工厂 1 的预期结果可能是:

<表类="s-表"><头>任务名称组织路径<正文>任务一我的公司/工厂 1/维护任务二我的公司/工厂 1/运营任务三我的公司/工厂 1任务四我的公司/工厂 1/运营

最佳答案

django-treebeard 将物化路径存储在 path 中像这样的字符串形式的列:000100020005002I .在此示例中,以下行是其祖先(假设默认步长为 4):

0001
00010002
000100020005
000100020005002I

django-treebeard 所做的是在 Python 中将页面路径拆分为上述位,然后执行数据库查询,如下所示:

Organization.objects.filter(path__in=['0001', '00010002', '000100020005'])`

为了避免 n+1 查询问题,我们需要避免在 Python 中拆分路径,并通过子查询在数据库中执行祖先查找。

模式匹配可用于查看祖先路径是否包含在子路径中:00010002火柴000100020005002I当候选人的路径被用作相关组织路径的模式时:

000100020005002I LIKE 00010002%  --- equals true
SELECT  
organization.path,
ARRAY(
SELECT
name
FROM
organization o_
WHERE
organization.path LIKE o_.path || '%'
)
FROM
organization
<表类="s-表"><头>组织路径数组<正文>0001{根目录}00010001{root, org_a}00010002{根, org_b}000100020001{root, org_b, org_b1}

Django 不提供开箱即用的解决方案来切换 .filter(path__startswith='pattern') 中的参数。查找(在我们这里的例子中是必需的)。这就是我使用 RawSQL 表达式的原因。

>>> from django.db.models.expressions import RawSQL

>>> orgs = Organization.objects.annotate(
ancestors=RawSQL(
"""
ARRAY(
SELECT name FROM organization o_
WHERE organization.path LIKE o_.path || '%%'
)
FROM organization
""",
params=[],
)
)

>>> orgs[0].ancestors
['Root', "Org 1", "Org 2", "Org 3"]

关于django - 使用 Django Treebeard 获取祖先时如何防止 N+1 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71796356/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com