Запрос данных из Джанго - PullRequest
0 голосов
/ 05 августа 2011

Вот как выглядит моя модель:

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 этого Visitor.

Мне нужно рассчитать среднее время посетителей на сайте, которое будет суммой времени для каждого посетителя на Action.site, деленное на количество посетителей.

Я мог бы запросить это с помощью SQL, но я бы хотел сохранить свой запрос как Djangonic, насколько это возможно, и я все еще очень запутан со сложными запросами.

1 Ответ

2 голосов
/ 05 августа 2011

Для конкретного объекта 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.

...