Jan Mejor
Jan Mejor

Reputation: 161

Save calculated value as a model field

As a follow up to my eariler question I have a new one. How can I save this calculated value as a model field. I would like to use it in my views and templates to order list by this field.

My models:

class Tournament(models.Model):
   name = models.CharField(max_length=100)
   date = models.DateTimeField('date')
   player_num = models.IntegerField(verbose_name="")
   points = models.FloatField(default=1000.00)
   def get_rating(self):
       return self.points / 1000.00

class TournamentStandings(models.Model):
   tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
   player = models.ForeignKey(Player, on_delete=models.CASCADE)
   player_place = models.FloatField(verbose_name=u"")
   player_points = models.FloatField(verbose_name="", 
   blank=True) #added for testing to save the calculated value in it
   @property 
   def get_player_points(self, obj):
       return obj.tournament.player_num * obj.tournament.get_rating() - 
       obj.tournament.get_rating()*(obj.player_place - 1.00)

   def save(self, *args, **kwargs):
       self.player_points = self.get_player_points   
       super(TournamentStandings, self).save(*args, **kwargs)



   def __float__(self):
     return self.player_points

Funny as on the admin list I have a column where player_points are calculated correctly but when I add a new model instance and try to save it I get this error : 'TournamentStandings' object has no attribute 'get_player_points'. Is it bacause I am trying to do a "self" save and my calculation is (self, obj) ?? Any hints are wellcome.

Upvotes: 1

Views: 3192

Answers (2)

Jan Mejor
Jan Mejor

Reputation: 161

Posting a working solution to my problem. No need for parentheses.

First I have fixed Tournament model, so I could save get_rating as a field:

class Tournament(models.Model):
    name = models.CharField(max_length=100)
    rating = models.FloatField(verbose_name="Rating", blank=True)

    @property
    def get_rating(self):
        return (self.points) / (1000.00)

    def save(self, *args, **kwargs):
        self.rating = self.get_rating
        super(Tournament, self).save(*args, **kwargs)

    def __float__(self):
        return self.rating

When I had this I tried to copy it to second model. Problem was that I could not get it to work due to related obj I was calling in my calculation. But! I have managed to assign this values to variables inside get_player_points and now all is working as intended:

class TournamentStandings(models.Model):
    tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
    player = models.ForeignKey(Player, on_delete=models.CASCADE)
    player_place = models.FloatField(verbose_name="")
    player_points = models.FloatField(verbose_name="", blank=True)

    @property
    def get_player_points(self):
        player_num = float(self.tournament.player_num)
        rating = float(self.tournament.rating)
        player_points = float(rating*player_num-rating*(self.player_place - 1.00))
        return player_points

    def save(self, *args, **kwargs):
        self.player_points = self.get_player_points
        super(TournamentStandings, self).save(*args, **kwargs)

    def __float__(self):
        return self.player_points

And this works! Any thoughts on improvements I could make are wellcome ofc.

Upvotes: 1

Asher
Asher

Reputation: 697

get_player_points() is a method and requires parentheses.

def save(self, *args, **kwargs):
     self.player_points = self.get_player_points() 

Upvotes: 0

Related Questions