This is my models
class Person(models.Model):
name = models.CharField(max_length=50)
is_group_member = models.BooleanField(default=False)
class Group(models.Model):
members = models.ManyToManyField(Person)
@receiver(post_save, sender=Group)
def set_group_member_type(sender, instance, created, **kwargs):
if created:
# change the all group members' type
I am trying to update is_group_member
field with signal.
When a group is created with members, then i will filter and retrieve all the person who are group member, then i will change the is_group_member
value to True
Can anyone help me to achieve this?
You can do that, but usually not by signals, since the group is created before the members are added. The trigger will thus be fired before there are members.
Furthermore it is likely not a good idea at all to define such field. If you later remove a member from a group, or add other members, it will be hard to update all the members accordingly. A person might still be a member of a different group. It is a form of data duplication, and it turns out that synchronizing data, is usually a harder problem than it looks.
It therefore is better to either add a property to your Person
model, or annotate your objects
queryset.
We can add a property that checks if the Person
is a member of a group. This will perform a query to the database, for each person where we query this:
class Person(models.Model):
name = models.CharField(max_length=50)
@property
def is_group_member(self):
return Group.objects.filter(members=self).exists()
objects
managerWe can annotate the objects
manager, such that it will run a subquery for each Person
in the queryset. We can add this for example to the objects
manager:
from django.db.models import Exists, OuterRef
class PersonManager(models.Manager):
def get_queryset(self):
from app.models import Group
return super().get_queryset().annotate(
is_group_member=Exists(Group.objects.filter(members=OuterRef('pk')))
)
We can then add the manager to the Person
class:
class Person(models.Model):
name = models.CharField(max_length=50)
objects = PersonManager()