【问题标题】:Django: Count only the latest object after grouping by monthDjango:按月分组后仅计算最新对象
【发布时间】:2019-11-15 03:45:00
【问题描述】:

我正在构建一个基于 django 的应用程序来收集有关某个软件用户的统计信息。

目标是显示一个图表,其中包含每个月使用某个版本的用户数量。

这是模型:

class Installation(models.Model):
    userid = models.IntegerField()
    version = models.CharField(max_length=25)
    timestamp = models.DateTimeField(auto_now=True)

timestamp 是收集用户数据的时间。

示例表如下所示:

| userid | version | timestamp |
|------------------------------|
|   1    |  3.1    |<sometime> |
|------------------------------|
|   2    |  3.1    |<sometime> |
|------------------------------|
|   1    |  3.2    |<sometime> |
|------------------------------|
|   3    |  3.1    |<sometime> |

&lt;sometime&gt; 代表同一个月的不同时间戳。 显示userid = 1在同一个月内升级到3.2版本。

这是我的方法:

version_by_month = Installation.objects
                   .annotate(month=TruncMonth('timestamp'))
                   .values('month', 'version')
                   .annotate(Count('userid', distinct=True))

但它有一个问题,即两个版本都会计算一个用户。例如,对于 3.13.2 两个版本,它都计算 userid = 1,并将使用 version = 3.1 的用户的计数返回为 3,实际上应该是 2。

我希望每个月都有一个输出,如果用户更改了他的版本,那么只有最新提交的版本应该被计算在内。

上面显示的表的预期查询集应该是这样的:

[{'month': datetime.datetime(2019, 7, 1, 0, 0, tzinfo=<UTC>), 'version': 3.1, 'num': 2},
{'month': datetime.datetime(2019, 7, 1, 0, 0, tzinfo=<UTC>), 'version': 3.2, 'num': 1}]

【问题讨论】:

    标签: django postgresql django-models


    【解决方案1】:

    好吧,我注意到这已经过去了一天多一点,没有答案。虽然我不会说 Django,但我无法提供直接的解决方案。但也许我可以为您指明正确的方向。
    您需要通过首先按用户消除多个版本来减少计数范围。在直接 sql 中,这可以通过一个子选择来完成,它只返回每个用户的最大版本,外部选择计算结果。

    -- setup
    create table django_count(userid integer, version numeric, dttz timestamp with time zone);
    insert into django_count(userid, version, dttz ) 
     values (1, 3.1, now()-interval '1 month')
          , (2, 3.1, now()-interval '1 month' + interval '3 days')
          , (1, 3.2, now()-interval '1 month' + interval '5 days') 
          , (3, 3.1, now()-interval '1 month' + interval '7 days') ;
    select * from django_count order by version desc;      
    
    -- count query. This is what you need in raw sql.
    select version, count(*)
      from (
            select userid, max(version) as Version, date_trunc('month',dttz) as "For Month"
              from django_count
             group by userid, date_trunc('month',dttz) 
           ) m
     group by version
     order by version;
    

    如果你能适应 Django,我很乐意提供帮助,如果不能,我很抱歉,我无法提供进一步的帮助。祝你好运。

    【讨论】:

      猜你喜欢
      • 2011-04-08
      • 2017-09-23
      • 1970-01-01
      • 1970-01-01
      • 2013-05-13
      • 2020-10-21
      • 1970-01-01
      • 2014-10-14
      • 1970-01-01
      相关资源
      最近更新 更多