• 【Django多对多使用through自定义中间表详解】


    Django多对多使用through自定义中间表详解

    多对多中间表详解

    我们都知道对于ManyToMany字段,Django采用的是第三张中间表的方式。通过这第三张表,来关联ManyToMany的双方。下面我们根据一个具体的例子,详细解说中间表的使用。

    默认中间表

    class Person(models.Model):
        name = models.CharField(max_length=128)
    
        def __str__(self):
            return self.name
    
    
    class Group(models.Model):
        name = models.CharField(max_length=128)
        members = models.ManyToManyField(Person)
    
        def __str__(self):
            return self.name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在Group模型中,通过members字段,以ManyToMany方式与Person模型建立了关系。
    让我们来看看,中间表是个什么样子的:
    在这里插入图片描述
    首先有一列id,这是Django默认添加的,没什么好说的。然后是Group和Person的id列,这是默认情况下,Django关联两张表的方式。如果你要设置关联的列,可以使用to_field参数。

    可见在中间表中,并不是将两张表的数据都保存在一起,而是通过id的关联进行映射。

    通过through自定义中间表

    一般情况,普通的多对多已经够用,无需自己创建第三张关系表。但是某些情况可能更复杂一点,比如如果你想保存某个人加入某个分组的时间呢?想保存进组的原因呢?

    Django提供了一个through参数,用于指定中间模型,你可以将类似进组时间,邀请原因等其他字段放在这个中间模型内。例子如下:

    modle:

    from django.db import models
    
    
    class Person(models.Model):
        name = models.CharField(max_length=128)
    
        def __str__(self):
            return self.name
    
    
    class Group(models.Model):
        name = models.CharField(max_length=128)
        members = models.ManyToManyField(Person, through='Membership')
    
        def __str__(self):
            return self.name
    
    
    class Membership(models.Model):
        person = models.ForeignKey(Person, on_delete=models.CASCADE)
        group = models.ForeignKey(Group, on_delete=models.CASCADE)
        date_joined = models.DateField()  # 进组时间
        invite_reason = models.CharField(max_length=64)  # 邀请原因
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    view:

    class PersonViews(ModelViewSet):
    
        queryset = Person.objects.filter()
        serializer_class = PersonSerializers
    
    
    class GroupViews(ModelViewSet):
    
        queryset = Group.objects.filter()
        serializer_class = GroupSerializers
    
    
    class MembershipViews(ModelViewSet):
    
        queryset = Membership.objects.filter()
        serializer_class = MembershipSerializers
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    serializer:

    from .models import Person, Group, Membership
    
    
    class MembershipSerializers(serializers.ModelSerializer):
    
        class Meta:
            model = Membership
            fields = '__all__'
    
    
    class PersonSerializers(serializers.ModelSerializer):
    
        class Meta:
            model = Person
            fields = '__all__'
    
    
    class GroupSerializers(serializers.ModelSerializer):
    
        def to_representation(self, instance):
            representation = super(GroupSerializers, self).to_representation(instance)
            representation['members'] = []
            for i in PersonSerializers(instance.members, many=True).data:
                reason = MembershipSerializers(instance.membership_set.get(group=instance.id, person=i['id'])).data['invite_reason']
                i['invite_reason'] = reason
                representation['members'].append(i)
            return representation
    
        class Meta:
            model = Group
            fields = '__all__'
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述
    reason = MembershipSerializers(instance.membership_set.get(group=instance.id, person=i[‘id’])).data[‘invite_reason’]
    instance.membership_set.get(group=instance.id, person=i[‘id’]) group和person联合查出邀请原因
    person和group模型上membership对象的默认名称都将为membership_set.所以通过instance.membership_set.get()可以查看group下的所有关系

    person下的所有membership:

        # def to_representation(self, instance):
        #     representation = super(PersonSerializers, self).to_representation(instance)
        #     representation['reason'] = MembershipSerializers(instance.membership_set, many=True).data
        #     return representation
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    使用 PAI-DSW x Free Prompt Editing图像编辑算法,开发个人AIGC绘图小助理
    API性能监控 【ApiHelp】-- 组件Enhance 代码实现 ~ ASM字节码增强
    Address already in dse_JVM_Bind。端口莫名被占用【占用8080端口!!!】
    Java接口
    X-ray Photoelectron Spectroscopy (XPS)——* 化学位移
    365天挑战LeetCode1000题——Day 035 每日一题 + 二分查找 13
    深入理解红黑树
    python查找替换:查找空行,空行前后添加```,```中间添加 # + 空格 + 空行后遇到的第1行文字?
    idean集成maven环境
    【无标题】
  • 原文地址:https://blog.csdn.net/qq_24822271/article/details/125421883