here is an example about how to use signal with many to many field (post like and post comments models),
and in my example i have :
like model (Intermediary table for User and Post tables) : the user can add 1 record only in Intermediary table for each post , which means (unique_together = ['user_like', 'post_like']) for this type of many to many relations you can use 'm2m_changed' signals ,
comment model (Intermediary table for User and Post tables): the user can add many records in Intermediary table for each post , (without unique_together ), for this i just use 'post_save, post_delete' signals , but you can use also 'pre_save, pre_delete' if you like ,
and here is both usage example :
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save, post_delete, m2m_changed
from django.dispatch import receiver
class Post(models.Model):
post_user = models.ForeignKey(User,related_name='post_user_related', on_delete=models.CASCADE)
post_title = models.CharField(max_length=100)
post_description = models.TextField()
post_image = models.ImageField(upload_to='post_dir', null=True, blank=True)
post_created_date = models.DateTimeField(auto_now_add=True)
post_updated_date = models.DateTimeField(auto_now=True)
post_comments = models.ManyToManyField(
User,
through="Comments",
related_name="post_comments"
)
p_like = models.ManyToManyField(
User, blank=True,
through="LikeIntermediary",
related_name="post_like_rel"
)
class LikeIntermediary(models.Model):
user_like = models.ForeignKey(User ,related_name="related_user_like", on_delete=models.CASCADE)
post_like = models.ForeignKey(Post ,related_name="related_post_like", on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user_like} - {self.post_like} "
class Meta:
unique_together = ['user_like', 'post_like']
@receiver(m2m_changed, sender=LikeIntermediary)
def like_updated_channels(sender, instance, **kwargs):
print('this m2m_changed receiver is called, the instance is post id', instance.id)
class Comments(models.Model):
cmt_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="related_comments_user")
cmt_post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="related_comments_post")
cmt_created_date = models.DateTimeField(auto_now_add=True)
cmt_comment_body = models.TextField()
cmt_created = models.DateTimeField(auto_now_add=True)
cmt_updated = models.DateTimeField(auto_now=True)
@receiver(post_save, sender=Comments)
def comments_updated_channels(sender, instance, created, **kwargs):
print('this post_save receiver is called, the instance post id', instance.cmt_post.id)
@receiver(post_delete, sender=Comments)
def comments_deleted_channels(sender, instance, **kwargs):
print('this post_save receiver is called, the instance post id', instance.cmt_post.id)
notes :
- the instance with 'm2m_changed' it is a post object .
- the instance with 'post_save and post_delete' it is a comment object
this is just an example , and change it based on your case/requirements.
i hope this helpful
Concern
as thesender
object, or change the model name toProject
insteadConcern
. – InfusibleConcern
was actually an abstract base class. Edited now. – Regain