user2536650
user2536650

Reputation:

How to filter Django object to get top X number of objects with highest property value

So I have a class called Hero with 150 objects. Each object has a property Winrate. I want to get the top 12 heros based on winrate.

class Hero(models.Model):

    hero_name = models.CharField(max_length=20, default = 'Dota 2 Hero') 
    hero_id = models.IntegerField()

    def __str__(self):
        return str(self.hero_id)
    def get_winrate(self):
        wins = len(Match.objects.filter(heros_won = Hero.objects.get(hero_id = self.hero_id)))
        losses = len(Match.objects.filter(heros_lost  = Hero.objects.get(hero_id = self.hero_id)))
        if wins + losses != 0:
            return round((wins / (wins + losses)),2)
        else:
            return 0 
    winrate = property(get_winrate)

I tried alot of filters but couldn't get it to work.

Upvotes: 0

Views: 589

Answers (1)

Emilio Conte
Emilio Conte

Reputation: 1145

I would make winrate an attribute of your Hero class as following.

class Hero(models.Model):

    hero_name = models.CharField(max_length=20, default = 'Dota 2 Hero') 
    hero_id = models.IntegerField()
    winrate = models.IntegerField()

    def _get_winrate(self):
        wins = len(Match.objects.filter(heros_won = Hero.objects.get(hero_id = self.hero_id)))
        losses = len(Match.objects.filter(heros_lost  = Hero.objects.get(hero_id = self.hero_id)))
        if wins + losses != 0:
            return round((wins / (wins + losses)),2)
        else:
            return 0 

    def save(*args, **kwargs):
        self.winrate = self._getwinrate()
        return super().save(*args, **kwargs)

Then you'll be able to order your request.

super_heroes = Hero.objects.order_by('-winrate')[:12]

EDIT: you shouldn't use len() on a queryset but count() like this:

wins = Match.objects.filter(heros_won=self.pk).count()

Why don't you use the natural primary key instead of this hero_id?

Upvotes: 1

Related Questions