Django对一对多相关对象的聚合查询

5 投票
2 回答
5889 浏览
提问于 2025-04-15 22:44

这是我简化后的模型:

class Item(models.Model):
    pass

class TrackingPoint(models.Model):
    item = models.ForeignKey(Item)
    created = models.DateField()
    data = models.IntegerField()

    class Meta:
        unique_together = ('item', 'created')

在我的应用程序的很多地方,我需要获取一组Item,并为每个项目添加来自每个项目最新的TrackingPointdata字段的注释,这些TrackingPoint是按照created字段排序的。例如,Item类的实例i1有3个TrackingPoint

tp1 = TrackingPoint(item=i1, created=date(2010,5,15), data=23)
tp2 = TrackingPoint(item=i1, created=date(2010,5,14), data=21)
tp3 = TrackingPoint(item=i1, created=date(2010,5,12), data=120)

我需要一个查询来获取i1实例,并用tp1.data字段的值进行注释,因为tp1是按照created字段排序后最新的跟踪点。这个查询还应该返回那些根本没有任何TrackingPointItem。如果可以的话,我更倾向于不使用QuerySetextra方法来实现这一点。

这是我到目前为止尝试的……但失败了 :(

Item.objects.annotate(max_created=Max('trackingpoint__created'),
                      data=Avg('trackingpoint__data')).filter(trackingpoint__created=F('max_created'))

有什么想法吗?

2 个回答

2

这不是直接回答你问题的内容,但如果你不一定需要你描述的那种解决方案,或许你会对“每组最大的n个”这个方法感兴趣。你可以看看我在类似问题上的回答:

获取不同类别中最新对象的Django查询

-- 这个方法应该直接适用于你的情况:

 items = Item.objects.annotate(tracking_point_created=Max('trackingpoint__created')) 
 trackingpoints = TrackingPoint.objects.filter(created__in=[b.tracking_point_created for b in items])

请注意,如果在TrackingPoint模型中,created日期有重复,第二行可能会产生模糊的结果。

8

这里有一个查询,可以提供(跟踪点,项目)配对:

TrackingPoint.objects.annotate(max=Max('item__trackingpoint__created')).filter(max=F('created')).select_related('item').order_by('created')

你需要单独查询那些没有跟踪点的项目。

撰写回答