Django細(xì)致講解多對多使用through自定義中間表方法
多對多中間表詳解
我們都知道對于ManyToMany字段,Django采用的是第三張中間表的方式。通過這第三張表,來關(guān)聯(lián)ManyToMany的雙方。下面我們根據(jù)一個具體的例子,詳細(xì)解說中間表的使用。
默認(rèn)中間表
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模型建立了關(guān)系。
讓我們來看看,中間表是個什么樣子的:

首先有一列id,這是Django默認(rèn)添加的,沒什么好說的。然后是Group和Person的id列,這是默認(rèn)情況下,Django關(guān)聯(lián)兩張表的方式。如果你要設(shè)置關(guān)聯(lián)的列,可以使用to_field參數(shù)。
可見在中間表中,并不是將兩張表的數(shù)據(jù)都保存在一起,而是通過id的關(guān)聯(lián)進行映射。
通過through自定義中間表
一般情況,普通的多對多已經(jīng)夠用,無需自己創(chuàng)建第三張關(guān)系表。但是某些情況可能更復(fù)雜一點,比如如果你想保存某個人加入某個分組的時間呢?想保存進組的原因呢?
Django提供了一個through參數(shù),用于指定中間模型,你可以將類似進組時間,邀請原因等其他字段放在這個中間模型內(nèi)。例子如下:
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 = MembershipSerializersserializer:
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關(guān)系,Django在啟動時,會自動在其關(guān)聯(lián)的模型上建立"[model]_set"的屬性,就想常規(guī)的多對一關(guān)系一樣——實際上他就是常規(guī)的多對一關(guān)系,只不過Person讓其充當(dāng)另外的角色罷了。

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聯(lián)合查出邀請原因
person和group模型上membership對象的默認(rèn)名稱都將為membership_set.所以通過instance.membership_set.get()可以查看group下的所有關(guān)系
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


到此這篇關(guān)于Django細(xì)致講解多對多使用through自定義中間表方法的文章就介紹到這了,更多相關(guān)Django through自定義中間表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
anaconda如何創(chuàng)建和刪除環(huán)境
這篇文章主要介紹了anaconda如何創(chuàng)建和刪除環(huán)境,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
Python基礎(chǔ)之列表常見操作經(jīng)典實例詳解
這篇文章主要介紹了Python基礎(chǔ)之列表常見操作,結(jié)合實例形式詳細(xì)分析了Python列表創(chuàng)建方式、內(nèi)置函數(shù)與相關(guān)使用技巧,需要的朋友可以參考下2020-02-02
Python中使用sqlalchemy操作數(shù)據(jù)庫的問題總結(jié)
在探索使用?FastAPI,?SQLAlchemy,?Pydantic,Redis,?JWT?構(gòu)建的項目的時候,其中數(shù)據(jù)庫訪問采用SQLAlchemy,并采用異步方式,這篇文章主要介紹了在Python中使用sqlalchemy來操作數(shù)據(jù)庫的幾個小總結(jié),需要的朋友可以參考下2024-08-08

