gpt4 book ai didi

django - 使用 Django ORM (CROSS JOIN) 计算组合

转载 作者:行者123 更新时间:2023-12-03 10:09:24 24 4
gpt4 key购买 nike

我有三个相关的模型:Process , FactorLevel .一个 ProcessFactor 具有多对多关系s 和 Factor将有一个或多个 Level s。我正在尝试计算 Level 的所有组合s 涉及 Process .这很容易用 Python 的 itertools 实现。作为模型方法,但执行速度有点慢,所以我想弄清楚如何使用 Django ORM 在 SQL 中执行此计算。
楷模:

class Process(models.Model):
factors = models.ManyToManyField(Factor, blank = True)

class Factor(models.Model):
...

class Level(models.Model):
factor = models.ForeignKey(Factor, on_delete=models.CASCADE)
示例:进程 'Running'涉及三个 Factor s ( 'Distance' , 'Climb' , 'Surface' ) 每个由多个 Level 组成s ( 'Long'/ 'Short' , 'Flat'/ 'Hilly' , 'Road'/ 'Mixed'/ 'Trail' )。计算 SQL 中的组合将涉及通过首先确定多少 Factor 来构建查询。 s 参与(在本例中为 3)并执行 CROSS JOIN所有级别的多次。
在 SQL 中,这可以这样完成:
WITH foo AS
(SELECT * FROM Level
WHERE Level.factor_id IN
(SELECT ProcessFactors.factor_id FROM ProcessFactors WHERE process_id = 1)
)
SELECT a1.*, a2.*, a3.*
FROM foo a1
CROSS JOIN foo a2
CROSS JOIN foo a3
WHERE (a1.factor_id < a2.factor_id) AND (a2.factor_id < a3.factor_id)
结果:
a1.name | a2.name | a3.name
--------------------------
Long | Flat | Road
Long | Flat | Mixed
Long | Flat | Trail
Long | Hilly | Road
Long | Hilly | Mixed
Long | Hilly | Trail
Short | Flat | Road
Short | Flat | Mixed
Short | Flat | Trail
Short | Hilly | Road
Short | Hilly | Mixed
Short | Hilly | Trail
目前,我已将此实现为 Process 上的一种方法。模型为:
def level_combinations(self):
levels = []
for factor in self.factors.all():
levels.append(Level.objects.filter(factor = factor))

combinations = []
for levels in itertools.product(*levels):
combination = {}

combination["levels"] = levels

combinations.append(combination)

return combinations
这是否可以使用 Django ORM 或者它是否足够复杂以至于它应该作为原始查询实现以提高 Python 代码实现的速度?
有一个关于 performing CROSS JOIN in Django ORM 的类似问题从几年前(大约 Django v1.3 看起来)似乎没有引起太多关注(作者决定只使用 Python itertools)。

最佳答案

from itertools import groupby, product

def level_combinations(self):
# We need order by factor_id for proper grouping
levels = Level.objects.filter(factor__process=self).order_by('factor_id')
# [{'name': 'Long', 'factor_id': 1, ...},
# {'name': 'Short', 'factor_id': 1, ...},
# {'name': 'Flat', 'factor_id': 2, ...},
# {'name': 'Hilly', 'factor_id': 2, ...}]

groups = [list(group) for _, group in groupby(levels, lambda l: l.factor_id)]
# [[{'name': 'Long', 'factor_id': 1, ...},
# {'name': 'Short', 'factor_id': 1, ...}],
# [{'name': 'Flat', 'factor_id': 2, ...},
# {'name': 'Hilly', 'factor_id': 2, ...}]]

# Note: don't forget, that product is iterator/generator, not list
return product(*groups)
如果顺序无关紧要,那么:
def level_combinations(self):
levels = Level.objects.filter(factor__process=self)
groups = {}
for level in levels:
groups.setdefault(level.factor_id, []).append(level)
return product(*groups.values())

关于django - 使用 Django ORM (CROSS JOIN) 计算组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34949995/

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