Question

I have the following model:

class Vote(models.Model):
    voter = models.ForeignKey(User)
    target = model.ForeignKey(User)
    timestamp = models.DateTimeField()
    game = models.ForeignKey(Game)
    step = model.IntegerField()
    type = models.ForeignKey(VoteType)

I need to select the most voted target and in case of ties select the target who got the earliest vote. Is it possible using Django ORM?

UPDATE: Actually I have also three more field inside Vote: game, turn and type (I added them to the code above), I need to select the winner according to the previous constraint given a particular game, turn and type (i.e. something like .filter(game=1, step=2, type=3))

Was it helpful?

Solution

You can use annotation to select the vote count and the earliest vote time for each user, and then order by the annotated fields and select the first:

from django.db.models import Count, Min

winner = User.objects.annotate(vote_count=Count('vote_set'))\
    .annotate(first_vote_time=Min('vote_set__timestamp'))\
    .order_by('-vote_count', 'first_vote_time')[0]

UPDATE: You can apply the following filter to count only the votes for a specific game:

.filter(vote_set__game=game, vote_set__step=step, vote_set__type=type)

The double underscore allows you to filter on attributes of related objects.

Be sure to apply the filter before the annotations, so that only the correct votes will be counted, and be sure that all filter conditions for the votes are within the same filter call. Why you have to do the latter is explained here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top