cross instance calculations in django queryset

拜拜、爱过 提交于 2019-12-24 10:55:45

问题


Not sure that it's (a) doable and (b) if I formulate the task correctly. Perhaps the right way is refactoring the db design, but I would appreciate any opinion on that.

I have a model in django app, where I track the times a user enters and exits a certain page (via either form submission or just closing the broswer window). I do tracking using django channels, but it does not matter in this case.

The model looks like:

class TimeStamp(models.Model):
    class Meta:
        get_latest_by = 'enter_time'

    page_name = models.CharField(max_length=1000)
    participant = models.ForeignKey(to=Participant, related_name='timestamps')
    timestamp = models.DateTimeField()
    enter_exit_type = models.CharField(max_length=1000, choices=ENTEREXITTYPES,)

What I need to do is to calculate how much time a user spends on this page. So I need to loop through all records of Timestamp for the specific user, and calculate time difference between records of 'enter' and 'exit' types records.

So the db data may look like:

id  timestamp  enter_exit_type
1  20:12:12  enter
2  20:12:13  exit
3  20:18:12  enter
4  20:21:12  exit
5  20:41:12  enter

so what is the right way to produce a resulting queryset that look like:

id  time_spent_sec  
1  0:01  
2  3:00 

The last 'enter' record is ignored because there is no corresponding 'exit' record. The record 1 in resulting queryset is difference between timestamps in ids 2 and 1. The record 2 in resulting queryset is difference between timestamps in ids 4 and 3.

I can just loop through the records, looking for the nearest 'exit' record and calculate it but I was thinking if there is a simpler solution?


回答1:


It's possible:

1) Use the approach here to group by user if you want to get answer for all users in one query.

2) filter out the last unclosed entry with enter_exit_type == 'enter'.

3) .annotate(timestamp_with_sign=Case(When(enter_exit_type='exit', then=F('timestamp') * -1), default=F('timestamp'), )

4) Sum() by the timestamp_with_sign field.

I'm not sure, that F('timestamp') would work, you may need to search for the way to convert it to unix time.




回答2:


This model structure may not be sufficient for your requirement. So I would suggest to change your model as,

class TimeStamp(models.Model):
    class Meta:
        get_latest_by = 'enter_time'

    page_name = models.CharField(max_length=1000)
    participant = models.ForeignKey(Musician, related_name='timestamps')
    enter = models.DateTimeField()
    exit = models.DateTimeField(null=True, blank=True)

Then you will get the data as,

from django.db.models import F, Sum, ExpressionWrapper, DurationField

TimeStamp.objects.values(
    'participant').annotate(
    sum_time_diff=Sum(
        ExpressionWrapper(F('exit') - F('enter'), output_field=DurationField())
    )
)

The response be like,

<QuerySet [{'participant': 1, 'sum_time_diff': datetime.timedelta(0, 7)}, {'participant': 2, 'sum_time_diff': datetime.timedelta(0, 2)}]>


来源:https://stackoverflow.com/questions/51667183/cross-instance-calculations-in-django-queryset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!