Django - 按日期和平均值查询聚合

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django - 按日期和平均值查询聚合相关的知识,希望对你有一定的参考价值。

我有一个应用程序,其中Gym与许多Surveys(多对多)相关联,而Survey有许多Answers

Answer有一个数字value,它与SurveyGym有关。

models.朋友

class DateTimeModel(models.Model):
    creation_date = models.DateTimeField(verbose_name=_('Creation Date'), auto_now_add=True, db_index=True)
    edit_date = models.DateTimeField(verbose_name=_('Last Edit Date'), auto_now=True, db_index=True)
    ...


class Gym(DateTimeModel):
    name = models.CharField(max_length=250)
    ...


class Survey(DateTimeModel):
    text = models.CharField(max_length=500)
    valid_from = models.DateTimeField()
    valid_to = models.DateTimeField()
    gyms = models.ManyToManyField(Gym)
    ...


class Answer(DateTimeModel):
    value = models.IntegerField()
    survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
    gym = models.ForeignKey(Gym, on_delete=models.PROTECT)
    ...

我需要在一天之内获得特定健身房的投票分配。这很容易实现:

views.朋友

class VotesDistributionByDayViewSet(APIView):
    @staticmethod
    def get(request, gym_id, survey_id):
        votes_by_date = Answer.objects.filter(gym_id=gym_id, survey_id=survey_id)
            .annotate(day=TruncDay('creation_date'))
            .values("day")
            .annotate(count=Count('gym_id'))
            .order_by('day')

        return Response({
            'votes_by_gym': votes_by_date,
        })

这将返回以下响应(这是正确的):

{
    "votes_by_gym": [
        {
            "day": "2018-06-11T00:00:00+02:00",
            "count": 15
        },
        {
            "day": "2018-06-12T00:00:00+02:00",
            "count": 6
        },
        {
            "day": "2018-06-13T00:00:00+02:00",
            "count": 17
        },
        {
            "day": "2018-06-14T00:00:00+02:00",
            "count": 12
        },
        ...

现在我需要按天返回所有健身房的平均答案数。我尝试了以下查询:

        avg_votes_by_date = Answer.objects
            .exclude(gym_id=8) 
            .filter(survey_id=survey_id) 
            .annotate(day=TruncDay('creation_date')) 
            .values("day") 
            .annotate(count_answers=Count('gym_id')) 
            .annotate(count_gym=Count('gym_id', distinct=True)) 
            .order_by('day')

返回以下响应:

"avg_votes_by_date": [
        {
            "day": "2018-06-11T00:00:00+02:00",
            "count_answers": 15,
            "count_gym": 1
        },
        {
            "day": "2018-06-12T00:00:00+02:00",
            "count_answers": 6,
            "count_gym": 1
        },
        {
            "day": "2018-06-13T00:00:00+02:00",
            "count_answers": 17,
            "count_gym": 1
        },
        {
            "day": "2018-06-14T00:00:00+02:00",
            "count_answers": 12,
            "count_gym": 2
        },
        {
            "day": "2018-06-15T00:00:00+02:00",
            "count_answers": 29,
            "count_gym": 2
        },

如何使用count_answers / count_gym的结果添加第三个键?有没有更好的方法来获得这个平均值?

答案

对于第二个查询,我建议您在所选值中注释“count_answers”和“count_gym”,然后除以转换:

avg_votes_by_date = Answer.objects 
    .exclude(gym_id=8) 
    .filter(survey_id=survey_id) 
    .annotate(day=TruncDay('creation_date')) 
    .values('day') 
    .annotate(count_answers=Count('gym_id')) 
    .annotate(count_gym=Count('gym_id', distinct=True)) 
    .annotate(avg=Cast(F('count_answers'), FloatField()) / Cast(F('count_gym'), FloatField())) 
    .order_by('day')

以上是关于Django - 按日期和平均值查询聚合的主要内容,如果未能解决你的问题,请参考以下文章

按日期和组聚合并在大查询中填写缺失的日期

SQL查询按时间段到日期聚合

注释总和的 Django 聚合平均值(1.6.5)

Django 查询集按时间间隔聚合

如何按日期级别制作汇总表

Mongoose 聚合不按输入日期过滤