Для конкретного объекта 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, либо в коде, подобном следующему.
По крайней мере, предлагаемое решение максимально использует ORM Django.