Django-Group by和Count by是唯一的



我有以下型号:

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)

我想获得帖子浏览量计数,按一天中的小时分组,并且是唯一的
例如,如果用户在上午10点看到一篇帖子20次,则只应计算一次。我得到的帖子在小时内按视图(不是唯一的视图(如下:

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_idhourpost_id一起获得独特的视图。ORM有可能做到这一点吗?

,你可以做到这一点

from django.db.models import Count
result = PostView.objects.values(
"created__hour",
"post",
"user"
).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 Answer

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'}]>

你需要按两次分组。CCD_ 4和CCD_ 5上的第一次以及CCD_ 6上的现有结果集上的第二次。

答案很长:

由于查询分为两个级别(日期级别和唯一用户(,因此需要两个查询。

在第一步中,对post_hour创建的帖子进行分组。没有这个基本的聚合结果将显示错误的值。

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(,存在CCD_ 8行。现在要计算这两行,需要额外的查询。

通过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        |
+---------------+----------+

在这里,我使用了SQLite特定的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方法让我们按照一般的Djangoorder_bydistinct注入SQL特定的函数和结果。SQLite在.上不支持distinct

最新更新