具有manytomanyfield的Django过滤器

时间:2019-10-03 15:17:26

标签: django django-models django-orm django-signals

这是我的模特

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

我正在尝试用信号更新is_group_member字段。

创建具有成员的组时,我将过滤并检索所有属于组成员的人,然后将is_group_member值更改为True

有人可以帮助我实现这一目标吗?

1 个答案:

答案 0 :(得分:0)

您可以这样做,但通常不是通过信号来 ,因为在添加成员之前会先创建组。因此,在有成员之前 将触发该触发器。

此外,定义这样的字段可能完全不是个好主意。如果以后从组中删除一个成员或添加其他成员,将很难相应地更新所有成员。一个人可能仍然是另一个组的成员。这是数据重复的一种形式,事实证明,同步数据通常比看起来要难得多。

因此,最好将属性添加到Person模型中,或注释objects查询集。

选项1:添加属性

我们可以添加一个属性来检查Person是否是组的成员。这将对我们查询此数据库的每个人执行对数据库的查询:

class Person(models.Model):
    name = models.CharField(max_length=50)

    @property
    def is_group_member(self):
        return Group.objects.filter(members=self).exists()

选项2:自定义objects经理

我们可以注释objects管理器,以便它将为查询集中的每个Person运行一个子查询。例如,我们可以将其添加到objects管理器中:

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')))
        )

然后我们可以将经理添加到Person类中:

class Person(models.Model):
    name = models.CharField(max_length=50)

    objects = PersonManager()