在Django中如何对多个字段进行聚合?

huangapple go评论105阅读模式
英文:

How to aggregate over multiple fields in Django?

问题

我有一个名为Trade的Django模型,用于存储多个市场的交易信息。这些对象每5分钟时间戳一次,我需要按市场日期时间进行聚合。

在性能方面,最佳解决方案是什么?

如您所见,我可以提取所需时间戳的列表,进行迭代和数据聚合,但我担心这不是最有效的解决方案。

这是我的代码:

  1. from django.db.models import Sum, Avg
  2. # 按时间排序对象
  3. qs = Trade.objects.all().order_by("-datetime")
  4. # 提取唯一时间戳
  5. dts = qs.values_list("datetime", flat=True).distinct()
  6. for dt in dts:
  7. cum_a = qs.filter(datetime=dt).aggregate(num_a=Sum('amount'))['num_a']
  8. cum_t = qs.filter(datetime=dt).aggregate(num_t=Sum('trades'))['num_t']
  9. avg_p = qs.filter(datetime=dt).aggregate(avg_p=Avg('price'))['avg_p']
  10. # 存储聚合数据

希望这对您有所帮助。

英文:

I have a Dango model Trade that store trades information for several markets. The objects are timestamped at every 5 minutes and I need to aggregate them by market and by datetime.

What is the best solution to do that with performance in mind ?

As you can see below, I could extract a list of the desired timestamps, iterate and aggregate data but I'm afraid it's not the most efficient solution.

  1. class Trade(TimestampedModel):
  2. market = models.ForeignKey(Market, on_delete=models.CASCADE, null=True)
  3. datetime = models.DateTimeField(null=True)
  4. amount = models.FloatField(null=True)
  5. price = models.FloatField(null=True)
  6. trades = models.FloatField(null=True)

This is my code:

  1. from django.db.models import Sum, Avg
  2. # Time order object
  3. qs = Trade.objects.all().order_by("-datetime")
  4. # Extract unique timestamps
  5. dts = qs.values_list("datetime", flat=True).distinct()
  6. for dt in dts:
  7. cum_a = qs.filter(datetime=dt).aggregate(num_a=Sum('amount'))['num_a']
  8. cum_t = qs.filter(datetime=dt).aggregate(num_t=Sum('trades'))['num_t']
  9. avg_p = qs.filter(datetime=dt).aggregate(avg_p=Avg('price'))['avg_p']
  10. ....
  11. # Store aggregated data

答案1

得分: 1

  1. django.db.models 中导入 Sum, Avg
  2. qs = Trade.objects.values('datetime').order_by('datetime').annotate(
  3. cum_a=Sum('amount'),
  4. cum_t=Sum('trades'),
  5. avg_p=Avg('price')
  6. )
  7. 你可以这样迭代
  8. for row in qs:
  9. print(row["datetime"], row["cum_a"], row["cum_t"], row["avg_p"])
英文:

Try this:)

  1. from django.db.models import Sum, Avg
  2. qs = Trade.objects.values('datetime').order_by('datetime').annotate(
  3. cum_a=Sum('amount'),
  4. cum_t=Sum('trades'),
  5. avg_p=Avg('price')
  6. )

You iterate like that:

  1. for row in qs:
  2. print(row["datetime"], row["cum_a"], row["cum_t"], row["avg_p"])

On SQL side you are grouping by datetime and running aggregation for each group.

  1. SELECT "datetime", SUM("amount") AS "cum_a", SUM("trades") AS "cum_t", AVG("price") AS "avg_p"
  2. FROM "Trade"
  3. GROUP BY "datetime"
  4. ORDER BY "datetime"

if you want to group by market too:

  1. qs = Trade.objects.values('datetime', 'market').order_by('datetime', 'market') \
  2. .annotate(
  3. cum_a=Sum('amount'),
  4. cum_t=Sum('trades'),
  5. avg_p=Avg('price')
  6. )
  7. for row in qs:
  8. print(row["datetime"], row["market"], row["cum_a"], row["cum_t"], row["avg_p"])

huangapple
  • 本文由 发表于 2023年6月26日 14:41:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76554116.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定