Search code examples
pythondjangopython-decorators

How can I make a decorator in models.py?


I have a football Team class in my django Model. I made 3 methods of win, draw and lose where the self.Points_of_the_season will be modified accordingly ( +3 for win, +1 for draw and +0 for lose). But when I wrote those methods, I have to change the self.Match_Played with each call of the 3 methods. How can I make a decorator called @play_match which will add 1 to the concerned field?

This is the code of models.py:

class Team(models.Model):
    Team_name = models.CharField(max_length=255)
    Foundation_year = models.IntegerField()
    Points_of_season = models.IntegerField(default=0)
    Match_Played = models.IntegerField(default=0)
    League = models.ForeignKey(League, on_delete=models.CASCADE)

    def __str__(self):
        return f"{self.Team_name}-{self.Foundation_year}"

    @play_match
    def win(self):
        self.Points_of_season += 3

    @play_match
    def draw(self):
        self.Points_of_season += 1

    @play_match
    def lose(self):
        pass

Solution

  • Like any other decorator. The argument to the decorator func should just be the function, then you define your subfunction inside the decorator function which will do the "decoration" before executing your function. So in this case, my decorator function is play_match and the which defines add_one which takes in the self argument so it can access the class variables. It then increments the Match_Played and then calls the function passed to the decorator.

    class Team:
        Team_Name = ""
        Foundation_year = 0
        Points_of_season = 0
        Match_Played = 0
        League = "league"
    
        def __str__(self):
            return f"{self.Team_name}-{self.Foundation_year}"
    
        def play_match(func):
            def add_one(self):
                self.Match_Played += 1
                func(self)
            return add_one
    
        @play_match
        def win(self):
            self.Points_of_season += 3
    
        @play_match
        def draw(self):
            self.Points_of_season += 1
    
        @play_match
        def lose(self):
            pass
    
    x = Team()
    x.win()
    print("Num matches: ", x.Match_Played)
    x.draw()
    print("Num matches: ", x.Match_Played)
    

    outputs:

    Num matches:  1
    Num matches:  2