Multiply column with Manytomany Count() from the same Model Django

Asked

Viewed 138 times

2

I have a model called Notificacoes and it has the following structure:

Notificacoes(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    users_interacting = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="u_interacting", null=True, blank=True)
    score = models.IntegerField(default=0)
    ....

When a user receives a notification, I create a record in that Model, being user the user who received the notification and users_interacting users who are interacting with the user in that notification.

In this way, I take advantage of the same notification and only add users who are interacting.

The problem is in score, i make a sum of Scores each save model, as each type of notification has a score:

score = Notificacoes.objects.filter(user = self.user).aggregate(Sum('score'))['score__sum']

It returns me the sum of all colors to that user. However, sometimes in a record I can have the score 5 for that type of notification users_interacting has 30 users participating in that notification. Then, the value of the score should be 5 * 30 but he accounts for only 5 because it’s just a notification.

How can I multiply the score with the users_interacting.count() of same model record?

Example:

notificacao_id | score | users_interacting
------------------------------------------
       1       |   5   |         1
------------------------------------------
       2       |  10   |         5

The sum I make returns -> score = 5 + 10 = 15.

What I would like to rotornar -> score = (5 * 1) + (10 * 5) = 55.

1 answer

1


All you need is a function that performs the weighted sum of scores. Unlike what I initially thought, this function needs to be an accepted method in aggregate, then external functions do not solve the problem. I researched a little and found that to realize a weighted sum within the aggregate, you need to pass an object which is the product scalar of two vectors. Try this solution:

score = Notificacoes.objects.all().annotate(
    total_weight=ExpressionWrapper(F('score') * F('users_interacting'), 
                                   output_field=IntegerField() ))

score.aggregate(total=Sum('total_weight'))
  • But in this case, how would I do it using Django’s ORM? I’m currently doing a for in the notifications and doing the multiplication in hand, (it’s working), but I believe there is a more performative way. Using Django’s ORM I don’t have access to the full users_interacting.

  • Oh yes. I thought sum that you had used was the built-in python, so just change the function. I’ll edit my answer. One minute

  • @Guilhermeia see now

  • It worked, thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.