• 【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

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    elementui el-dialog 动态生成多个,点击按钮打开对应的 dialog
    20天零基础自学Python | Day6 运算符大全
    Android 13 网络 Adb相关流程深入分析研究
    LeetCode 2322. 从树中删除边的最小分数 暴力+DFS+优化
    猿创征文| NoSQL数据库简介
    R语言和医学统计学(10):正态性和方差齐性检验
    浅析乡镇房地产产业现状及其对乡镇经济发展的推动力
    维格云数据回收站入门教程
    Mysql-varchar和text的区别
    JAVA并发编程——线程池详解
  • 原文地址:https://blog.csdn.net/qq_24822271/article/details/125421883