问题
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