user4923309
user4923309

Reputation:

Django best practice: where to put an aggregation method

I have a best-practice question:

I have a model Score which contains a value and a ForeignKey to another model. It's my aim to make it possible to call account.scores.total_score() and it will return the sum of the values of all scores in the account.

class Score(models.Model):
    value = models.IntegerField()
    account = models.ForeignKey(Account, related_name='scores')

I was thinking about writing a ScoreManager and ScoreQuerySet to handle this access easily.

class ScoreQuerySet(models.QuerySet):
    def total_score(self):
        return self.aggregate(Sum('value'))

class ScoreManager(models.Manager):
    use_for_related_fields = True

    def get_queryset(self):
        return ScoreQuerySet(self.model, using=self._db)

class Score(models.Model):
    value = models.IntegerField()
    account = models.ForeignKey(Account, related_name='scores')
    objects = ScoreManager()

This does only work if I call account.scores.all().total_score() but not directly with account.scores.total_score(). This doesn't work, because somehow my model does not register the new Manager and QuerySet on the relationship. But maybe this isn't the best practice, so I don't need to take time to fix this and should choose another way. So what do you guys think about this? Should I create a total_score() function in the Account model?

Thanks for your help!

Upvotes: 1

Views: 584

Answers (1)

bigblind
bigblind

Reputation: 12867

If you always need to calculate the total score associated with an account, why not add it as a method to your Account model?

class Account(models.Model): ...

def get_total_score(self):
    return self.scores.aggregate(Sum('value'))

# or even as a property:
@property
def total_score(self):
   return self.scores.aggregate(Sum('value'))

Upvotes: 1

Related Questions