#python #django
#python #django
Вопрос:
У меня есть объект Django с методом get_volume_sum(self)
, который возвращает значение с плавающей запятой, и я хотел бы запросить верхние n объектов с наибольшим значением, как я могу это сделать?
Например, я мог бы выполнить подобный цикл, но мне хотелось бы более элегантного решения.
vol = []
obj = []
for m in Market.object.filter(**args): # 3000 objects
sum = m.get_volume_sum()
vol.append(sum)
obj.append(m.id)
top = search_top_n(obj, vol, n)
И вот как выглядит метод:
# return sum of volume over last hours
def get_volume_sum(self, hours):
return Candle.objects.filter(market=self,
dt__gte=timezone.now()-timedelta(hours=hours)
).aggregate(models.Sum('vo'))
Из того, что я вижу здесь, даже с Python нет единого линейного решения.
Комментарии:
1. Как это
get_volume_sum
выглядит. Вы не можете фильтровать aQuerySet
на основе метода, поскольку база данных не знает о методах. Обычно лучше выполнять логику на стороне базы данных, поскольку это будет быстрее.2. привет @WillemVanOnsem спасибо за ответ, я добавил, как выглядит метод. Спасибо!
3. где это
hours
происходит вm.get_volume_sum()
?4.
hours
происходит из другого метода для другого объекта
Ответ №1:
Вы не должны фильтровать с помощью метода, это приведет к проблеме N 1: для 3’000 Market
объектов он сгенерирует дополнительные 3’0000 запросов для получения объемов.
Вы можете сделать это массово с помощью .annotate(…)
[Django-doc]:
from django.db.models import Sum
hours = 12 # some value for hours
Market.objects.filter(
**args,
candle__dt__gte=timezone.now()-timedelta(hours=hours),
).annotate(
candle_vol=Sum('candle__vo')
).order_by('-candle_vol')
Здесь, однако, есть небольшое предостережение: если нет связанных Candle
, то они Market
будут отфильтрованы. Мы можем предотвратить это, разрешив также Market
s без Candle
s с:
from django.db.models import Q, Sum
hours = 12 # some value for hours
Market.objects.filter(
Q(candle__dt__gte=timezone.now()-timedelta(hours=hours)) |
Q(candle=None),
**args
).annotate(
candle_vol=Sum('candle__vo')
).order_by('-candle_vol')