从Django查询数据

时间:2011-08-05 10:14:38

标签: django django-models django-queryset

这是我的模型结构:

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。跟踪始终由sessionsequence_no按升序排序。网站上的Visitors平均时间(即特定Action.host)是最高和最低Track.when之间Track.sequence_no(时间)之差除以{{Sessions 1 {} Visitor

我需要计算网站访问者的平均时间,即Action.site上每位访问者的时间总和除以访问者数量。

我可以使用SQL查询,但我想尽可能保持我的查询为Djangonic,而且我仍然对复杂查询感到非常遗憾。

1 个答案:

答案 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。