简体   繁体   中英

How to query Django objects based on a field value in the latest ForeignKey?

I have a Django application to store hourly price and volume (OHLCV candle) for several markets. What I'm trying to achieve is to compare the latest volume of all markets and set top10 = True to the 10 markets with the highest volume in the latest candle. What is the most efficient way to do that?

EDIT: The queryset should select all the most recent candle in every markets and sort them by volume. Then return the 10 markets the top 10 candles belong to.

models.py

class Market(models.Model):
    top10 = JSONField(null=True)


class Candle(models.Model):
    market = models.ForeignKey(Market, on_delete=models.CASCADE, related_name='candle', null=True)
    price = models.FloatField(null=True)
    volume = models.FloatField(null=True)
    dt = models.DateTimeField()

Finally, I've figured out the solution, I guess.

latest_distinct = Candle.objects.order_by('market__pk', '-dt').distinct('market__pk')
candle_top = Candle.objects.filter(id__in=latest_distinct).order_by('-volume')[:10]

for item in candle_top:
    item.market.top10 = True
    item.market.save() 

latest_distinct = Candle.objects.order_by('market__pk', '-dt').distinct('market__pk') will select latest candle record for every Market . candle_top = Candle.objects.filter(id__in=latest_distinct).order_by('-volume')[:10] will sort items in previous query in descending order and slice 10 greatest ones. Then you iterate over it setting each market.top10 to True

Notice that I'm assuming that Market 's top10 field is a boolean. You can substitute your own logic instead of item.market.top10 = True

I have found a solution to my own question by selecting the last candle in every markets with it primary key, and creating a list of lists with list element as [volume, pk] . Then I sort the nested lists by list element 0 volume and select top 10. It returns a list of desired markets:

import operator
v = [[m.candle.first().volume, m.candle.first().id] for m in Market.objects.all()]
top = sorted(v, key=operator.itemgetter(0))[-10:]
[Candle.objects.get(id=i).market for i in [t[1] for t in top]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM