Django- Group by 和 Count by unique 在一起
Django- Group by and Count by unique together
我有以下型号:
class Post(models.Model):
title = models.CharField(max_length=30)
class PostView(models.Model):
post = models.ForeignKey(Post, related_name='views', on_delete=models.CASCADE)
user = models.ForeignKey(get_user_model(), related_name='my_views')
created = models.DateTimeField(auto_now_add=True)
我想获得 post 观看次数,按一天中的小时分组并且是唯一的。
例如,如果用户在上午 10 点看到 post 20 次,则应只计算一次。
我在几个小时内按视图(不是唯一视图)获得 posts,如下所示:
from django.db.models.functions import TruncHour
from django.db.models import Count
qs = PostView.objects.all().annotate(
hour=TruncHour('created')
).values(
'hour'
).annotate(
c=Count('id')
).values('hour', 'c')
以上代码会将所有观看次数计算为总观看次数。我想通过 user_id
和 hour
以及 post_id
一起获得独特的观点。
可以用 ORM 做到这一点吗?
你可以做到,
from django.db.models import Count
result = PostView.objects.values(
<b>"created__hour",
"post",
"user"</b>
).annotate(count=Count("id"))
print(list(result))
# Result
# [{'created__hour': 17, 'post': 1, 'user': 1, 'count': 4}, {'created__hour': 17, 'post': 2, 'user': 1, 'count': 3}]
简答 SQL & Django
select a.day_hour, count(*) from (select strftime('%Y-%m-%d %H', created) as day_hour,
user_id, count(*) from post_postview
where post_id=1 group by strftime('%Y-%m-%d %H', created), user_id)
a group by a.day_hour
Django 答案
In [140]: rs = PostView.objects.filter(post_id=1).extra(
{'date_hour': u"strftime('%%Y-%%m-%%d %%H', created)"}).order_by('date_hour').values('user_id', 'date_hour').annotate(count=Count('user_id', distinct=True))
In [141]: rs
Out[141]: <QuerySet [{'date_hour': '2021-05-28 10',
'user_id': 2, 'count': 1}, {'date_hour': '2021-05-28 10',
'user_id': 3, 'count': 1}, {'date_hour': '2021-05-28 11',
'user_id': 2, 'count': 1}, {'date_hour': '2021-05-28 11',
'user_id': 3, 'count': 1}]>
In [142]: rs.values('date_hour').distinct()
Out[142]: <QuerySet [{'date_hour': '2021-05-28 10'},
{'date_hour': '2021-05-28 11'}]>
您需要分组两次。第一次在 date_hour
和 user_id
上,第二次在 date_hour
.
上的现有结果集上
长答案:
由于查询在两个级别(日期级别和唯一用户),因此您需要两个查询。
第一步,将 post_hour
创建的 post 分组。没有这个基本聚合结果将显示错误的值。
db.sqlite3> select strftime('%Y-%m-%d %H', created) as
day_hour, user_id, count(*) from post_postview where
post_id=1 group by strftime('%Y-%m-%d %H', created), user_id
+---------------+---------+----------+
| day_hour | user_id | count(*) |
+---------------+---------+----------+
| 2021-05-28 10 | 2 | 1 |
| 2021-05-28 10 | 3 | 2 |
| 2021-05-28 11 | 2 | 3 |
| 2021-05-28 11 | 3 | 2 |
+---------------+---------+----------+
如您所见,同一时间间隔(2021-05-28 10),
有 2
行。现在要计算这两行,需要额外的查询。
通过 day_hour
再次应用同一组,我们每小时得到结果。
select a.day_hour, count(*) from (select strftime('%Y-%m-%d
%H', created) as day_hour, user_id, count(*) from
post_postview where post_id=1 group by strftime('%Y-%m-%d
%H', created), user_id) a group by a.day_hour;
+---------------+----------+
| day_hour | count(*) |
+---------------+----------+
| 2021-05-28 10 | 2 |
| 2021-05-28 11 | 2 |
+---------------+----------+
这里我使用了SQL站点特定strftime
,这是重要的部分。
相同的代码被移植到 Django 作为
In [145]:
PostView.objects.filter(post_id=1).extra({'date_hour':
u"strftime('%%Y-%%m-%%d %%H',
created)"}).order_by('date_hour').values('user_id',
'date_hour').values('date_hour').distinct()
Out[145]: <QuerySet [{'date_hour': '2021-05-28 10'},
{'date_hour': '2021-05-28 11'}]>
extra
方法让您注入 SQL 特定函数,然后结果遵循通用 Django order_by
和 distinct
。 SQLite 不支持 distinct on。
我有以下型号:
class Post(models.Model):
title = models.CharField(max_length=30)
class PostView(models.Model):
post = models.ForeignKey(Post, related_name='views', on_delete=models.CASCADE)
user = models.ForeignKey(get_user_model(), related_name='my_views')
created = models.DateTimeField(auto_now_add=True)
我想获得 post 观看次数,按一天中的小时分组并且是唯一的。
例如,如果用户在上午 10 点看到 post 20 次,则应只计算一次。
我在几个小时内按视图(不是唯一视图)获得 posts,如下所示:
from django.db.models.functions import TruncHour
from django.db.models import Count
qs = PostView.objects.all().annotate(
hour=TruncHour('created')
).values(
'hour'
).annotate(
c=Count('id')
).values('hour', 'c')
以上代码会将所有观看次数计算为总观看次数。我想通过 user_id
和 hour
以及 post_id
一起获得独特的观点。
可以用 ORM 做到这一点吗?
你可以做到,
from django.db.models import Count
result = PostView.objects.values(
<b>"created__hour",
"post",
"user"</b>
).annotate(count=Count("id"))
print(list(result))
# Result
# [{'created__hour': 17, 'post': 1, 'user': 1, 'count': 4}, {'created__hour': 17, 'post': 2, 'user': 1, 'count': 3}]
简答 SQL & Django
select a.day_hour, count(*) from (select strftime('%Y-%m-%d %H', created) as day_hour,
user_id, count(*) from post_postview
where post_id=1 group by strftime('%Y-%m-%d %H', created), user_id)
a group by a.day_hour
Django 答案
In [140]: rs = PostView.objects.filter(post_id=1).extra(
{'date_hour': u"strftime('%%Y-%%m-%%d %%H', created)"}).order_by('date_hour').values('user_id', 'date_hour').annotate(count=Count('user_id', distinct=True))
In [141]: rs
Out[141]: <QuerySet [{'date_hour': '2021-05-28 10',
'user_id': 2, 'count': 1}, {'date_hour': '2021-05-28 10',
'user_id': 3, 'count': 1}, {'date_hour': '2021-05-28 11',
'user_id': 2, 'count': 1}, {'date_hour': '2021-05-28 11',
'user_id': 3, 'count': 1}]>
In [142]: rs.values('date_hour').distinct()
Out[142]: <QuerySet [{'date_hour': '2021-05-28 10'},
{'date_hour': '2021-05-28 11'}]>
您需要分组两次。第一次在 date_hour
和 user_id
上,第二次在 date_hour
.
长答案:
由于查询在两个级别(日期级别和唯一用户),因此您需要两个查询。
第一步,将 post_hour
创建的 post 分组。没有这个基本聚合结果将显示错误的值。
db.sqlite3> select strftime('%Y-%m-%d %H', created) as
day_hour, user_id, count(*) from post_postview where
post_id=1 group by strftime('%Y-%m-%d %H', created), user_id
+---------------+---------+----------+
| day_hour | user_id | count(*) |
+---------------+---------+----------+
| 2021-05-28 10 | 2 | 1 |
| 2021-05-28 10 | 3 | 2 |
| 2021-05-28 11 | 2 | 3 |
| 2021-05-28 11 | 3 | 2 |
+---------------+---------+----------+
如您所见,同一时间间隔(2021-05-28 10),
有 2
行。现在要计算这两行,需要额外的查询。
通过 day_hour
再次应用同一组,我们每小时得到结果。
select a.day_hour, count(*) from (select strftime('%Y-%m-%d
%H', created) as day_hour, user_id, count(*) from
post_postview where post_id=1 group by strftime('%Y-%m-%d
%H', created), user_id) a group by a.day_hour;
+---------------+----------+
| day_hour | count(*) |
+---------------+----------+
| 2021-05-28 10 | 2 |
| 2021-05-28 11 | 2 |
+---------------+----------+
这里我使用了SQL站点特定strftime
,这是重要的部分。
相同的代码被移植到 Django 作为
In [145]:
PostView.objects.filter(post_id=1).extra({'date_hour':
u"strftime('%%Y-%%m-%%d %%H',
created)"}).order_by('date_hour').values('user_id',
'date_hour').values('date_hour').distinct()
Out[145]: <QuerySet [{'date_hour': '2021-05-28 10'},
{'date_hour': '2021-05-28 11'}]>
extra
方法让您注入 SQL 特定函数,然后结果遵循通用 Django order_by
和 distinct
。 SQLite 不支持 distinct on。