I have three models as below:
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
class PersonSession(models.Model):
start_time = models.DateTimeField(auto_now_add=True)
end_time = models.DateTimeField(null=True,
blank=True)
person = models.ForeignKey(Person, related_name='sessions')
class GameSession(models.Model):
score = models.PositiveIntegerFeild()
person_session = models.ForeignKey(PersonSession, related_name='games')
Now I want get list of persons with calculated all scores they get plus the time they spend in all their game sessions and branch sessions, the query I currently use is as below:
Person.objects.annotate(game_score=Sum(Case(When(Q(sessions__games__isnull=True),
then=0),
default=F('sessions__games__score'),
output=models.PositiveIntegerField())))\
.annotate(spent_time=Sum(Case(When(Q(branch_sessions__isnull=False) &
Q(branch_sessions__end_time__isnull=False),
then=ExpressionWrapper(ExtractHour(ExpressionWrapper(F('sessions__end_time')-F('sessions__start_time'),
output_field=models.TimeField()),
output=models.PositiveIntegerField()) * 60 + \
ExtractMinute(ExpressionWrapper(F('sessions__end_time')-F('sessions__start_time'),
output_field=models.TimeField()),
output=models.PositiveIntegerField()),
output_field=models.PositiveIntegerField())),
default=0,
output=models.PositiveIntegerField()))) \
.annotate(total_score=F('game_score') + F('spent_time') * SCORE_MIN)\
.order_by('-total_score')
The problem is that this query join all tables together so for each PersonSession
may be we have many GameSession
and the resulting table contains the repeated row of a person session which causes time of a person sessions sums together repeatedly and generates a wrong result.
In a sql query I must first construct a subtable with sum of game socres and then join that table with persons session, but I do not know how could this possible in django?
I am using django 1.11 and postgres.