Django:如何使用第一个注释进行注释,按用户分组并再次注释?

时间:2018-01-17 13:33:43

标签: django

我是一个带有ReadingSession模型的Django(1.11)项目,如下所示:

class ReadingSession(models.Model):
    user = models.ForeignKey(User)        
    started_at = models.DateTimeField()
    ended_at = models.DateTimeField()

我想在一个数据库请求中显示每个给定用户的阅读会话持续时间总和。

在其他尝试中,我尝试过:

usernames = ['user1', 'user2',] 
q = ReadingSession.objects.filter(user__username__in=usernames)\
    .annotate(duration=Func(F('ended_at'), F('started_at'), function='age'))\
    .order_by().values('user') \
    .annotate(total_duration=Sum('duration'))\
    .values('user', 'total_duration')
print q

但它失败了:

Traceback (most recent call last):
 File ".../misc_queries.py", line 74, in <module>
test_query()
 File ".../misc_queries.py", line 51, in test_query
.annotate(total_duration=Sum('duration'))
 File ".../lib/python2.7/site-packages/django/db/models/query.py", line 945, in annotate
clone.query.add_annotation(annotation, alias, is_summary=False)
 File "/.../lib/python2.7/site-packages/django/db/models/sql/query.py", line 973, in add_annotation
summarize=is_summary)
 File ".../lib/python2.7/site-packages/django/db/models/aggregates.py", line 19, in resolve_expression
c = super(Aggregate, self).resolve_expression(query, allow_joins, reuse, summarize)
File ".../lib/python2.7/site-packages/django/db/models/expressions.py", line 548, in resolve_expression
c.source_expressions[pos] = arg.resolve_expression(query, allow_joins, reuse, summarize, for_save)
File "/.../lib/python2.7/site-packages/django/db/models/expressions.py", line 471, in resolve_expression
return query.resolve_ref(self.name, allow_joins, reuse, summarize)
File "..../local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1472, in resolve_ref
  return self.annotation_select[name]
KeyError: 'duration'

这是有道理的,因为&#34;值(&#39;用户&#39;)&#34;语句过滤了&#39; filter()&#39;返回的字段。声明。 但另一方面,如果我添加&#39;持续时间&#39;在第一个&#39;值()&#39;声明,结果不再由用户分组。

你看到我在这里做错了什么或者你有另一种方法来实现这个目标吗?

提前致谢!

2 个答案:

答案 0 :(得分:0)

我确定你可以将它作为一个复杂的数据库查询来实现,但是如何在视图中返回数据并迭代它呢?

queryset = ReadingSession.objects.all()

results = {}
for record in queryset:
    if not record.user in results:
        results[record.user] = timedelta(microseconds=0)
    time_diff = record.ended_at - record.started_at
    results[record.user] += time_diff

return results

这将返回结果字典[用户名] = [会话时间总和]

答案 1 :(得分:0)

您可能可以使用Window函数: https://docs.djangoproject.com/en/3.1/ref/models/expressions/#window-functions

from django.db import models

usernames = ('user1', 'user2',)

q = ReadingSession.objects.filter(
    user__username__in=usernames
).annotate(
    duration=models.Func(models.F('ended_at'), models.F('started_at'), function='age')
).annotate(
    total_duration=models.Window(
        expression=models.Sum('duration'),
        partition_by=[models.F('user')],
    )
).values('user', 'total_duration')

print q