Django ORM: получение строк на основе максимального значения столбца - PullRequest
3 голосов
/ 15 сентября 2009

У меня есть класс 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 ]

2 голосов
/ 15 сентября 2009

Если я правильно понял, вам нужен список объектов Marketorder, который содержит каждый 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/

Edit: Это должно получить один ордер Market с наибольшим сообщенным временем для определенного ордера

order = (
    Marketorders.objects
        .filter(orderid=the_orderid)
        .filter(reportedtime=(
            Marketorders.objects
                .filter(orderid=the_orderid)
                .aggregate(Max('reportedtime'))
                ['reportedtime__max']
        ))
)
0 голосов
/ 15 сентября 2009

У вас есть веская причина, почему вы не используете ForeignKey или (в вашем случае лучше) ManyToManyField . Эти поля представляют реляционную структуру ваших моделей.

Кроме того, необязательно объявлять идентификатор pk-поля. если pk не определен, django добавляет id.

Код ниже разрешает orm-запросы, подобные этому:

   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)

По соглашению все названия классов моделей являются единственными. Джанго автоматически делает его множественным в разных местах.

больше по запросам (фильтрация, сортировка, сложные поиски) . обязательно прочитайте.

...