0

Django - Annotate with count across ManytoMany relationships

I am not able to find the way to annotate a queryset with a count of how many times an element is used in a many-to-many relationship.

class Profile(models.Model):
    [...]
    # Profile can have multiple roles
    roles = models.ManyToManyField('Role', blank=True)
    [...]

class Role(models.Model):
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    name = models.CharField(blank=True, max_length=30)
    description = models.CharField(blank=True, max_length=300)
    [...] 

For example I would have 5 roles:

  • Role1
  • Role2
  • Role3
  • Role4
  • Role5

And 2 profiles with following roles assigned:

  • Profile1
    • Role 1
    • Role 2
  • Profile2
    • Role 1
    • Role 3
    • Role 4

I need to have the oposite than @ha-duy:

Profile: name, role_count=2
Profile: name, role_count=3

Any ideas?

Thanks!

1 Answers1

1

One Idea:

In the same view where you update the rolls loop through the many to many fields and return the length. then update the model appropriately.

Better Idea:

create a custom save method for the profile model so that every time .save() is called it will calculate the number of roles and update that field. more info on that here. custom save method on model - django

Maybe this will help because it won't be persistent in the DB but will give you the info:

class Test(models.Model):
name = models.CharField(max_length=10,)
category = models.ManyToManyField(cats)

def __str__(self):
    x = self.category.all()
    y = len(x) 
    return 'this is an item count ' + str(y)

or if you want it in object form:

add this to the model.

    def dataBlock(self):
       x = self.category.all()
       y = len(x) 
       return {
           'name': self.name,
           'cat_length': y,
       }
CR Python
  • 146
  • 6
  • Thanks @cr-python for your response, I know that it is not in the problem description but it I am looking for something that do not persist in the DB. The roles count is an example, I need to solve the same case with other columns like get the description of the longer role name. – Daniel Aron Goldenberg Nov 17 '19 at 00:19
  • I followed your "better idea" of saving a calculated value on the data base and it is working. THANK! I am updating the values when a m2m_changed signal is called – Daniel Aron Goldenberg Nov 18 '19 at 00:22