选择具有最大字段/列值的实例/行(每个字段/列)(分组依据)

时间:2020-08-24 18:49:43

标签: django django-orm

所以,我有以下模型:

class Computer(models.Model):
    hostname = models.CharField(primary_key=True, max_length=6)
    <other computer info fields>

class ComputerRecord(models.Model):
    id = models.AutoField(primary_key=True)
    pc = models.ForeignKey(Computer, on_delete=models.CASCADE)
    ts = models.DateTimeField(blank=False)
    <other computerrecord info fields>

我想获取每个ts(计算机模型)具有最大pc的行/计算机记录实例

在sql中将是这样的:

SELECT hub_computerrecord.*
FROM hub_computerrecord
JOIN (
    SELECT pc_id, MAX(ts) AS max_ts
    FROM hub_computerrecord
    GROUP BY pc_id
) AS maxs ON hub_computerrecord.pc_id = maxs.pc_id
WHERE hub_computerrecord.ts = maxs.max_ts;

注意(编辑):ComputerRecord实例很多(超过10000个),因此效率低下的任何事情都将不起作用

2 个答案:

答案 0 :(得分:3)

尝试一下

from django.db.models import Max, F

qs = ComputerRecord.objects.annotate(
    max=Max('pc__computerrecord__ts')
).filter(
    ts=F('max')
)

是的,此表单表达式不能在OP中建立 exact SQL查询,但是它会产生相同的结果(可能存在一些性能问题,不确定矩阵)

或者,您也可以使用 raw() 方法执行原始SQL,

raw_query = """
SELECT hub_computerrecord.*
FROM hub_computerrecord
JOIN (
    SELECT pc_id, MAX(ts) AS max_ts
    FROM hub_computerrecord
    GROUP BY pc_id
) AS maxs ON hub_computerrecord.pc_id = maxs.pc_id
WHERE hub_computerrecord.ts = maxs.max_ts;
"""

qs = ComputerRecord.objects.raw(raw_query)

答案 1 :(得分:1)

在ComputerRecord模型中添加一个布尔字段,例如max_status。用Computer对象的最大“ ts”值标识记录,并将其设置为True。因此,如果您为特定计算机型号拥有10000条记录,则在max_status字段中,一条记录将为True,其余所有9999条记录将为False。每种计算机型号只需执行一次。

下一次在ComputerRecord模型中添加新行时,只需将max_status值为True的新记录的“ ts”与现有记录的“ ts”进行比较。如果新记录具有较高的“ ts”值,则将此记录的max_status设置为True,并将先前记录的max_status更改为False,否则无需更改。

当您需要查找具有最大'ts'的ComputerRecord实例时,仅在max_status = True上查询