'Django add element in manytomany relationship inside the save method

I try to add the author field in viewed_by manytomany relationship when the model is saved but nothing is added and I don't know why. I also try to use signals with post_save but nothing it don't work. Please help me.

class Message(AbstractCreateUpdate):
    
    class TypeMessage(models.TextChoices):
        TEXT = "TEXT"
        EVENT = "EVENT"
        IDEA = "IDEA"
        UPDATE = "UPDATE"
        
    id = models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False)
    showcase = models.ForeignKey("Showcase",
                                 on_delete=models.CASCADE,
                                 related_name="messages",
                                 related_query_name="messages")
    author = models.ForeignKey(settings.AUTH_USER_MODEL,
                               on_delete=models.CASCADE,
                               related_name="messages",
                               related_query_name="messages")
    type_message = models.CharField(max_length=32,
                                    choices=TypeMessage.choices)
    viewed_by = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                       related_name="messages_visualize",
                                       related_query_name="messages_visualize",
                                       blank=True)
    
    class Meta(AbstractCreateUpdate.Meta):
        db_table = "message"
        verbose_name = _("Message")
        verbose_name_plural = _("Messages")
        
    def save(self, *args, **kwargs):
        message = super().save(*args,**kwargs)
        if not self.viewed_by.filter(id=self.author.id).exists():
            self.viewed_by.add(self.author)
        return message
        
    def __str__(self): return str(self.id)

Moreover, in another models with a custom manytomany relationship this script to save a fields in manytomany work.

class Project(AbstractFile,AbstractCreateUpdate):
    __link_site_help_text = _("Link del sito di contatto del progetto")
    __ended_at_help_text = _("Data di chiusura del progetto. Se null il progetto è aperto")
    __num_swipe_help_text = _("Il numero di swipe fatti dal progetto")
    __tags_help_text = _("I tags che identificano il progetto")
    
    id = models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False)
    creator = models.ForeignKey(settings.AUTH_USER_MODEL,
                                on_delete=models.SET_NULL,
                                null=True,
                                related_name="projects_created",
                                related_query_name="projects_created")
    
    name = models.CharField(_("name"),unique=True,max_length=64)
    description = models.TextField(_("description"),max_length=516,null=True,blank=True)

    
    image = models.ImageField(_("image"), blank=True, null=True,upload_to=image_path)
    link_site = models.TextField(_("link site"), blank=True, null=True,
                                 help_text=__link_site_help_text,
                                 max_length=516)
    
    ended_at = models.DateField(_("ended"),null=True, blank=True,
                                    help_text=__ended_at_help_text)
    num_swipe = models.PositiveBigIntegerField(_("number swipe"), default=0,
                                               help_text=__num_swipe_help_text)
    
    tags = models.ManyToManyField(ProjectTag,
                                  related_name="projects",
                                  related_query_name="projects",
                                  help_text=__tags_help_text,
                                  blank=True)
    
    users = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                   through="UserProject",
                                   through_fields=("project", "user"),
                                   related_name="projects",
                                   related_query_name="projects")
    
    class Meta(AbstractCreateUpdate.Meta):
        db_table = "project"
        verbose_name = _("Project")
        verbose_name_plural = _("Projects")
        constraints = [
            CheckConstraint(check=Q(ended_at__lte=Now()),name="check_ended_at"),
            CheckConstraint(check=Q(updated_at__gte=F('created_at')),name="check_project_updated_at")
        ]
    
    @property
    def ended(self):
        return self.ended_at.strftime('%d %B %Y')
    
    def save(self,*args, **kwargs):
        project = super().save(*args,**kwargs)
        self.setup_creator()
        return project
    
    def setup_creator(self):
        if not self.users.filter(id=self.creator.id).exists():
            self.users.add(self.creator)
    


Solution 1:[1]

The many to many relations are saved in a separate table, with your primary key and the foreign keys to reference the related models (in this case the user and the message).

With self.viewed_by.filter(id=self.author.id).exists() you're filtering the value of these primary key. Probably in your database exists a relation with the same primary key that the user. You need filter by the "user_id" or similar property:

self.viewed_by.filter(user_id=self.author.id).exists()

But, since you use settings.AUTH_USER_MODEL, best filter from user through the related_name:

self.author.messages_visualize.filter(message=self).exists()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tonio