Django计算聚合总数

时间:2016-12-29 00:17:47

标签: python django views aggregate annotate

我正在尝试构建一个基于用户ID聚合统计信息的表。这是第一次提出问题,如果我错过任何重要的话,请耐心等待。

以下是模型:

def stats(request):
  batting_stats = Batting.objects.values('player__id').annotate(
    fn=F('player__first_name'),
    ln=F('player__last_name'),
    total_hits=Sum(('hits'),output_field=FloatField()),
    total_at_bats=Sum(('at_bats'),output_field=FloatField()),
    avg=Avg('batting_average'),
    slg=Avg('slugging_percentage'),
    obp=Avg('on_base_percentage'),
    ops=Avg('on_base_plus_slugging_percentage'),
    )

  return render(request, 'stats.html', {
    'batting_stats': batting_stats,
    })

以下是观点:

{{1}}

我遇到的问题是avg,slg,obp和ops都是模型中的所有计算,并且在View中对它们求平均值是平均值,而不是根据玩家ID计算聚合的总数。

我尝试过使用Aggregate功能,但还没找到让它工作的方法。有没有办法结合Annotate和Aggregate的使用,这将允许我在单个玩家ID下合并统计数据并将相同的计算应用于总数?

1 个答案:

答案 0 :(得分:0)

正如我所看到的,实际上你需要对单个Batting实例和你的统计数据视图进行相同的计算。所以我将在一个函数中创建并从两个点调用它:

def count_averages(data, result_recipient=None):
    result_recipient = data if result_recipient=None else result_recipient
    result_recipient.total_bases = data.singles + (data.doubles * 2) + (data.triples * 3) + (data.home_runs * 4)
    result_recipient.extra_base_hits = data.doubles + data.triples + data.home_runs
    ...

def save(self, *args, **kwargs):
    count_averages(self)
    super(Batting, self).save(*args, **kwargs)

def stats(request):
    sum_of_all_batting_stats = Batting.objects.filter('player__id'=player__id).annotate(
      sum('singles'),
      sum('doubles'),
      sum('triples'),
      ...
    )
    batting_stats = {}
    count_averages(self, batting_stats)

    return render(request, 'stats.html', {
        'batting_stats': batting_stats,
    })

这不是100%有效的代码,但您应该有这样的想法:您将计算移动到分离的函数并调用2个不同的数据 - 1)一个Batting实例和2)所有Batting实例的总和。

P.S。如果每次为每个视图调用计算它,都可能导致性能问题。我建议将聚合的统计信息存储在db表或某个缓存中。