这是我的模型结构:
class Visitor(models.Model):
id = models.AutoField(primary_key=True)
class Session(models.Model):
id = models.AutoField(primary_key=True)
visit = models.ForeignKey(Visitor)
sequence_no = models.IntegerField(null=False)
class Track(models.Model):
id = models.AutoField(primary_key=True)
session = models.ForeignKey(Session)
action = models.ForeignKey(Action)
when = models.DateTimeField(null=False, auto_now_add=True)
sequence_no = models.IntegerField(null = False)
class Action(models.Model):
id = models.AutoField(primary_key=True)
url = models.CharField(max_length=65535, null=False)
host = models.IntegerField(null=False)
如您所见,每个Visitor
都有多个Sessions
;每个Session
都有多个Tracks
,每个Track
都有一个Action
。跟踪始终由session
和sequence_no
按升序排序。网站上的Visitors
平均时间(即特定Action.host
)是最高和最低Track.when
之间Track.sequence_no
(时间)之差除以{{Sessions
1 {} Visitor
。
我需要计算网站访问者的平均时间,即Action.site
上每位访问者的时间总和除以访问者数量。
我可以使用SQL查询,但我想尽可能保持我的查询为Djangonic,而且我仍然对复杂查询感到非常遗憾。
答案 0 :(得分:2)
对于特定的Action
对象,您可以收集有关会话的有趣数据:
from django.db.models import Min, Max
from yourapp.models import *
host = 1 # I suppose you want to calculate for each site
sessions = list(Session.objects.filter(
track__action__host=host,
).annotate(
start=Min('track__when'),
end=Max('track__when'),
).values('visit_id', 'start', 'end'))
你会得到以下内容:
[
{ 'visit_id': 1, 'start': datetime(...), 'end': datetime(...) },
{ 'visit_id': 1, 'start': datetime(...), 'end': datetime(...) },
{ 'visit_id': 2, 'start': datetime(...), 'end': datetime(...) },
....
]
现在只需从数据中获得所需的结果:
number_of_visitors = len(set(s['visit_id'] for s in sessions))
total_time = sum((s['end'] - s['start']).total_seconds() for s in sessions)
average_time_spent = total_time / number_of_visitors
另一种方法是使用两个查询而不是一个,并避免使用len(set(...))
代码段:
sessions = Session.objects.filter(
track__action__host=host,
).annotate(
start=Min('track__when'),
end=Max('track__when'),
)
number_of_visitors = sessions.values('visit_id').distict().count()
total_time = sum((s['end'] - s['start']).total_seconds()
for s in sessions.values('start', 'end'))
除了提供的聚合外,没有办法做实际的计算字段,所以你要么用原始SQL做,要么用这样的代码做。
至少建议的解决方案尽可能使用Django的ORM。