【问题标题】:Model objects to be grouped by date field in another model要在另一个模型中按日期字段分组的模型对象
【发布时间】:2020-04-06 09:49:23
【问题描述】:

我有两个模型,一个叫做评论,另一个叫做答案,从它的名字可以看出,一个评论有很多答案(正好 7 个),一个经典的一对多关系。

我可以用这种直截了当的关系、过滤、prefech_related 来做所有常见的事情,甚至只预取一些带有条件的答案。

现在,我想用当天的答案对象按审核日期进行分组,如您所见,我的问题是如何做到这一点,因为我将只用一个字段对许多对象进行分组,正常聚合在Django 只是求和,但我想要对象

我为此搜索了一段时间,但找不到可以使用 orm 生成查询集然后序列化它或在 SQL 中完成的解决方案

谢谢

编辑

用简单的话总结我的问题,我想按字段获取分组的所有对象,例如:如果日期 2019-12-12 有 10 个答案,那么而不是计算或求和的正常注释我想要得到这10个对象

再次感谢您

编辑 2

这是我的评论模型

class Review(model.Model):
    #other fields omitted
    submitted_at = models.DateTimeField()

    class Meta:
        ordering = ('-submitted_at',)

和我的答案模型

class Answer(models.Model):
    review = models.ForeignKey(
        Review, on_delete=models.CASCADE, related_name='answers')
    choice = models.ForeignKey(Choice, on_delete=models.CASCADE)
    question = models.ForeignKey(Question, on_delete=models.CASCADE)

    class Meta:
        ordering = ('id',)

正常输出的样本

  [
     {
      "submitted_at": "2019-10-08T16:13:36.356275+02:00",
      "answers": [
        {
          "question": 1,
          "choice": 4
        },
        {
          "question": 2,
          "choice": 4
        },
        {
          "question": 3,
          "choice": 4
        },
        {
          "question": 4,
          "choice": 4
        },
        {
          "question": 5,
          "choice": 7
        },
        {
          "question": 6,
          "choice": 7
        },
        {
          "question": 7,
          "choice": 11
        }
      ],
    },
    {
      "submitted_at": "2019-10-08T16:13:36.234108+02:00",
      "answers": [
        {
          "question": 1,
          "choice": 5
        },
        {
          "question": 2,
          "choice": 4
        },
        {
          "question": 3,
          "choice": 4
        },
        {
          "question": 4,
          "choice": 4
        },
        {
          "question": 5,
          "choice": 7
        },
        {
          "question": 6,
          "choice": 7
        },
        {
          "question": 7,
          "choice": 11
        }
      ],
    },
    {
      "submitted_at": "2019-10-08T16:13:36.168304+02:00",
      "answers": [
        {
          "question": 1,
          "choice": 1
        },
        {
          "question": 2,
          "choice": 1
        },
        {
          "question": 3,
          "choice": 1
        },
        {
          "question": 4,
          "choice": 1
        },
        {
          "question": 5,
          "choice": 8
        },
        {
          "question": 6,
          "choice": 8
        },
        {
          "question": 7,
          "choice": 10
        }
      ],
    }
  ]

在按提交_at 分组后仅包含日期部分的目标是这样的

  [
   {
      "submitted_at": "2019-10-08",
      "answers": [
        {
          "question": 1,
          "choice": 4
        },
        {
          "question": 2,
          "choice": 4
        },
        {
          "question": 3,
          "choice": 4
        },
        {
          "question": 4,
          "choice": 4
        },
        {
          "question": 5,
          "choice": 7
        },
        {
          "question": 6,
          "choice": 7
        },
        {
          "question": 7,
          "choice": 11
        },
        {
          "question": 1,
          "choice": 5
        },
        {
          "question": 2,
          "choice": 4
        },
        {
          "question": 3,
          "choice": 4
        },
        {
          "question": 4,
          "choice": 4
        },
        {
          "question": 5,
          "choice": 7
        },
        {
          "question": 6,
          "choice": 7
        },
        {
          "question": 7,
          "choice": 11
        },
        {
          "question": 1,
          "choice": 1
        },
        {
          "question": 2,
          "choice": 1
        },
        {
          "question": 3,
          "choice": 1
        },
        {
          "question": 4,
          "choice": 1
        },
        {
          "question": 5,
          "choice": 8
        },
        {
          "question": 6,
          "choice": 8
        },
        {
          "question": 7,
          "choice": 10
        }
      ],
    }
  ]

当然,如果我可以按问题分组会更好,但我认为这可能很难,所以让我们先尝试解决大问题

【问题讨论】:

  • 总是添加一些数据和样本输出以获得更快的答案
  • @Fact 如果有帮助,我很乐意从一开始就添加这些内容,但我对此表示怀疑。如果有帮助,我用一句话添加并抽象了我的问题,检查一下
  • 为此,取决于数据库,您必须使用分析函数,如 row_number、sum(column) Over()、avg(col) Over()、lead、lag、count(col) over() .同样,如果您可以生成一些数据和预期输出,这将有助于了解您到底想要什么。
  • @Fact 感谢您的帮助,我会尽力提供这些
  • 这就是方法,我只是添加了一个答案来帮助您理解我的意思,这可能不是您想要的,但鉴于缺乏明确性,这可能是我最好的猜测t 表的模式和实际数据。

标签: sql django django-models django-rest-framework django-orm


【解决方案1】:

可以通过以下方式进行基于字段的分组。

Answer.objects.values("review__submitted_at", "question__your_field_name", choice__your_field_name).annotate(Count("question__your_field_name")).order_by("question__your_field_name")

【讨论】:

  • 你确定吗?因为这会计算每一行的问题,并且它总是会产生 1,它不会进行分组,即使你的意思是聚合器函数,如 sum 和 count 这不是我要找的,或者这是我的问题,请阅读我的再仔细提问
  • 我在写评论之前已经尝试过,但它不起作用
  • answers.values("review__submitted_at", "question_id", 'choice_id').annotate(Count("question_id")).order_by("question_id")
  • { "review__submitted_at": "2019-01-08T16:00:55Z", "question_id": 1, "choice_id": 5, "question_id__count": 1 }
  • 添加更多实例并查看输出
【解决方案2】:

您在评论中猜对了 - 按日期时间戳分组,涵盖日期和评论 ID。 代码在 postgres 12 中运行。逻辑的核心在任何数据库中都保持不变

 With Reviews as 
 (
 Select '2019-10-08 12:13:36'::timestamp submitted_at, 100 reviewid Union all
 Select '2019-10-08 13:13:36'::timestamp, 100 Union all
 Select '2019-10-08 14:13:36'::timestamp,100
 ) 
 ,reviews_grouped_by_date as
  (
   Select Date_trunc('day',submitted_at) submitted_at , reviewid from Reviews
   group by date_trunc('day',submitted_at),reviewId
 )
,answers as
 (
 Select 1 question , 4 choice, 100 reviewId,'2019-10-08'::date dateans union all
 Select 2,4 ,100,'2019-10-08'::date union all
 Select 3,4 ,100,'2018-10-08'::date union all
 Select 1,4 ,200,'2019-10-08'::date
 )
Select answers.dateans, answers.question, answers.choice,answers.reviewid
From reviews_grouped_by_date 
JOIN answers ON reviews_grouped_by_date.reviewid=answers.reviewId
        AND reviews_grouped_by_date.submitted_at=answers.dateans

【讨论】:

  • 非常感谢您的帮助,我想我得到了一些使用 ORM 的灵感,或者即使我没有成功,我也知道使用 SQL 应该走哪条路
【解决方案3】:

您可以使用 Django QuerySet API 按日期过滤答案:

def get_answer_by_date(date):
    answers_by_date = Answer.objects.filter(review__submitted_at__date=date)

   return {"submitted_at":date, "answers":answers_by_date.values("question", "choice")}

https://docs.djangoproject.com/en/2.2/ref/models/querysets/#date

【讨论】:

  • 这肯定很简单,但我必须将它放在一个循环中才能为所有日期执行此操作,我希望通过 orm 或 sql 使用 db 层来执行此操作,因为对于大型数据集它会花点时间
猜你喜欢
  • 2015-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多