Django ORM:根据列的最大值获取行

时间:2009-09-15 12:31:02

标签: sql django greatest-n-per-group django-orm

我有一个类Marketorders,其中包含有关单个市场订单的信息,它们收集在市场快照中(由类Snapshot表示)。每个订单都可以出现在多个快照中,其中最新一行当然是相关的。

class Marketorders(models.Model):
    id = models.AutoField(primary_key=True)
    snapid = models.IntegerField()
    orderid = models.IntegerField()
    reportedtime = models.DateTimeField(null=True, blank=True)
    ...


class Snapshot(models.Model):
    id = models.IntegerField(primary_key=True)
    ...

我正在做的是在多个快照中获取所有订单以进行处理,但我想只包含每个订单的最新行。在SQL中我只会这样做:

SELECT m1.* FROM marketorders m1 WHERE reportedtime = (SELECT max(reportedtime)  
FROM marketorders m2 WHERE m2.orderid=m1.orderid);

或更好的联接:

SELECT m1.* FROM marketorders m1 LEFT JOIN marketorders m2 ON 
m1.orderid=m2.orderid AND m1.reportedtime < m2.reportedtime 
WHERE m2.orderid IS NULL;

然而,我无法弄清楚如何使用Django ORM来做到这一点。有没有原始SQL可以实现这个目的吗?

编辑:只是为了澄清问题。假设我们有以下市场营销人员(遗漏一切不重要且仅使用orderid,报告时间):

1, 09:00:00
1, 10:00:00
1, 12:00:00
2, 09:00:00
2, 10:00:00

如何使用ORM获得以下设置?

1, 12:00:00
2, 10:00:00

2 个答案:

答案 0 :(得分:2)

如果我理解正确,您需要一个Marketorder对象列表,其中包含每个orderid报告时间最长的每个Marketorder

这样的事情应该有效(免责声明:没有直接测试):

m_orders = Marketorders.objects.filter(id__in=(
    Marketorders.objects
        .values('orderid')
        .annotate(Max('reportedtime'))
        .values_list('id', flat=True)
))

进行文件检查:

http://docs.djangoproject.com/en/dev/topics/db/aggregation/

编辑: 这应该是一个具有特定订单的报告时间最长的单一Marketorder

order = (
    Marketorders.objects
        .filter(orderid=the_orderid)
        .filter(reportedtime=(
            Marketorders.objects
                .filter(orderid=the_orderid)
                .aggregate(Max('reportedtime'))
                ['reportedtime__max']
        ))
)

答案 1 :(得分:0)

你有充分的理由不使用ForeignKey或(在你的情况下更好)ManyToManyField。这些字段代表ur模型的关系结构。

此外,没有必要声明pk-field id。如果没有定义pk,django会添加id。

下面的代码允许像这样的orm-queries:

   m1 = Marketorder()
   m1.save() # important: primary key will be added in db
   s1 = Snapshot()
   s2 = Snapshot()
   s1.save()
   s2.save()
   m1.snapshots.add(s1)
   m1.snapshots.add(s2)
   m1.snapshots.all()
   m1.snapshots.order_by("id") # snapshots in relations with m1 
                               # ordered by id, that is added automatically
   s1.marketorder_set.all()    # reverse

以便查询

snapshot = Snapshot.objects.order_by('-id')[0] # order desc, pick first
marketorders = snapshot.marketorder_set.all()  # all marketorders in snapshot

或压缩

marketorders = Snapshot.objects.order_by('-id')[0].marketorder_set.all()

models.py

class Snapshot(models.Model):
    name = models.CharField(max_length=100)

class Marketorder(models.Model):
    snapshots = models.ManyToManyField(Snapshot)
    reportedtime = models.DateTimeField(auto_now= True)

按照惯例,所有模型类名称都是单数。 Django自动在不同的地方复数。

more on queries (filtering, sorting, complex lookups)。必读。