Django: считать только последний объект после группировки по месяцам - PullRequest
4 голосов
/ 04 июля 2019

Я создаю приложение на основе 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> |

<sometime> представляет различные временные метки одного и того же месяца.Он показывает, что userid = 1 обновлен до версии 3.2 в течение того же месяца.

Вот мой подход:

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

Но есть проблема, что он будет считать одного пользователя для двух версий,Например, он подсчитывает userid = 1 для обеих версий 3.1 и 3.2 и возвращает счет для пользователей, использующих 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}]

1 Ответ

0 голосов
/ 06 июля 2019

Ну, я заметил, что это чуть больше дня, без ответа.Пока я не могу дать прямого решения, так как не говорю на Джанго.Но, возможно, я могу указать вам правильное направление.
То, что вам нужно, - это уменьшить количество юниверсов, сначала удалив несколько версий пользователем.В прямом 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, я рад помочь, еслине извините, я не могу помочь дальше.Удачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...