Django: Concatenate two manytomany fields in one single field and save it in the database

69 Views Asked by At

I have these two models:

class Person(models.Model):
    name = models.CharField(max_length=200)
class Project(models.Model):
    project_info = models.CharField(max_length=200)
    project_manager = models.ManyToManyField(Person, related_name="project_manager")
    project_collaborator = models.ManyToManyField(Person, related_name="project_collaborator")

I want to save in the database the field "project_info" with this concatenated value: "project_manager & project_collaborator".

I tried to override the save method of the Project model:

    def save(self, *args, **kwargs):
        self.project_info = self.project_manager + '&' + self.project_collaborator
        super().save(*args, **kwargs)

but it returns me the error "unsupported operand type(s) for +: 'ManyRelatedManager' and 'str'".

1

There are 1 best solutions below

2
On

I would not save this as a separate field in the database, since it's already implicitly available on the model itself.

Three things:

  1. related_name is the name of the reverse attribute on the Person model(So 'project_manager' and 'project_collaborator' is probably not the right choice. Maybe 'managing_projects' and 'collaborating_projects'? That would allow you to access a person's projects through person.managing_projects and person.collaborating_projects.
  2. Is there only one project manager and collaborator on a project? In that case, you should use a ForeignKey instead of a ManyToManyField.
  3. You can't do self.project_manager + '&' + self.project_collaborator because these fields don't have a way to be converted to a string. Instead (If you use ForeignKeys like I said in point 2, you should use self.project_manager.name + '&' + self.project_collaborator.name

Then finally instead of saving this field seperately in the database, you could use a @property decorator to generate this field on the fly:

class Project(models.Model):
    project_manager = models.ForeignKey(Person, related_name="managing_projects")
    project_collaborator = models.ForeignKey(Person, related_name="collaborating_projects")
    
    @property
    def project_info(self):
        return self.project_manager.name + '&' + self.project_collaborator.name