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

在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)  # 邀請原因

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

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

從Membership角度,他是建立量到兩個模型(Group,Person)的多對1關系,Django在啟動時,會自動在其關聯的模型上建立"[model]_set"的屬性,就想常規的多對一關系一樣——實際上他就是常規的多對一關系,隻不過Person讓其充當另外的角色罷瞭。

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

到此這篇關於Django細致講解多對多使用through自定義中間表方法的文章就介紹到這瞭,更多相關Django through自定義中間表內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: