一,、前言
下面的講解都基于三張表:student(學(xué)生表)
,、course(課程表)
、student_course(學(xué)生課程中間表)
;
功能描述:有多個(gè)學(xué)生和多門(mén)課程,一個(gè)學(xué)生可以選修多門(mén)課程,。
它們的表結(jié)構(gòu)如下:
student 學(xué)生表
字段 說(shuō)明 id 學(xué)生id student_name 學(xué)生的姓名 course 學(xué)生選修的課程(多對(duì)多)
course 課程表
字段 說(shuō)明 id 課程id course_name 課程名
student_course 學(xué)生課程中間表
字段 說(shuō)明 id 中間表id student_id 學(xué)生id course_id 課程id
二,、創(chuàng)建多對(duì)多關(guān)系表
1. 自動(dòng)創(chuàng)建
1)通過(guò)django的ORM遷移功能可以方便自動(dòng)的建立多對(duì)多關(guān)系:
class Course ( models. Model) :
id = models. AutoField( primary_key= True )
course_name = models. CharField( max_length= 100 )
class Meta :
db_table = 'course'
class Student ( models. Model) :
id = models. AutoField( primary_key= True )
student_name = models. CharField( max_length= 100 )
course = models. ManyToManyField( to= Course)
2)在項(xiàng)目目錄下,依次執(zhí)行如下遷移命令:
python manage. py makemigrations
python manage. py migrate
3)遷移成功的話,就可以在數(shù)據(jù)庫(kù)中看到這三張表了:
2. 手動(dòng)創(chuàng)建
刪除student表的manyTomany字段,然后手動(dòng)創(chuàng)建中間表的orm模型即可:
class Course ( models. Model) :
id = models. AutoField( primary_key= True )
course_name = models. CharField( max_length= 100 )
class Meta :
db_table = 'course'
class Student ( models. Model) :
id = models. AutoField( primary_key= True )
student_name = models. CharField( max_length= 100 )
class Meta :
db_table = 'student'
class StudentAndCourse ( models. Model) :
id = models. AutoField( primary_key= True )
student = models. ForeignKey( to= Student, on_delete= models. DO_NOTHING)
course = models. ForeignKey( to= Course, on_delete= models. DO_NOTHING)
class Meta :
db_table = 'student_and_course'
三、多對(duì)多的使用
1. 前期準(zhǔn)備
我們先為學(xué)生表創(chuàng)建一個(gè)學(xué)生,姓名為:曲鳥(niǎo)
,學(xué)生ID為:1
:
2. 添加多對(duì)多數(shù)據(jù)及關(guān)系
1)創(chuàng)建單個(gè)新數(shù)據(jù)并建立關(guān)系
添加一個(gè)名為語(yǔ)文
的課程并與曲鳥(niǎo)
建立多對(duì)多的關(guān)系:
student= Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
student. course. create( course_name= "語(yǔ)文" ) # 創(chuàng)建名為語(yǔ)文的課程并建立關(guān)系
通過(guò)上面的代碼可以看出,只要student
是模型的Student
對(duì)象,就可以直接創(chuàng)建數(shù)據(jù)并建立關(guān)系,所以將之前查詢學(xué)生的代碼:
student= Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
改為下面這樣也是可以的:
student= Student. objects. filter ( id = 1 ) . first( ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
當(dāng)然,新創(chuàng)建一個(gè)學(xué)生再新建課程進(jìn)行關(guān)聯(lián)也是可以的:
student= Student. objects. create( student_name= "張三" ) # 創(chuàng)建名為張三的學(xué)生
student. course. create( course_name= "數(shù)學(xué)" ) # 創(chuàng)建名為數(shù)學(xué)的課程并建立關(guān)系
2)創(chuàng)建多個(gè)新數(shù)據(jù)并建立關(guān)系
如果直接使用批量添加數(shù)據(jù)(bulk_create)方法,是無(wú)法建立多對(duì)多的關(guān)系的,。
如果非要批量創(chuàng)建并建立關(guān)系的話,可以再批量創(chuàng)建數(shù)據(jù)的時(shí)候指定主鍵值,然后通過(guò)set方法進(jìn)行關(guān)聯(lián):
student = Student. objects. filter ( id = 1 ) . first( )
set_list = [ ]
a = 7
for name in [ '體育' , '美術(shù)' ] :
set_list. append( Course( course_name= name, id = a) ) # 手動(dòng)指定id
a += 1
aa = student. course. bulk_create( set_list) # 返回給aa的是一個(gè)列表,里面的元素為Course對(duì)象
student. course. set ( aa) # 通過(guò)set方法進(jìn)行關(guān)聯(lián)關(guān)系的建立
3)多對(duì)多建立關(guān)系add和set的區(qū)別
3.1 add
add接收一個(gè)Model對(duì)象,用于在原來(lái)存在的關(guān)系上進(jìn)行單條多對(duì)多關(guān)系的建立 (如果add的多對(duì)多關(guān)系原來(lái)已經(jīng)存在了,則保持不變) :
student = Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
course = Course. objects. get( id = 7 ) # 查詢id=7的課程
student. course. add( course)
如果想基于原來(lái)存在的關(guān)系,批量增加新的多對(duì)多關(guān)系,則可以這樣寫(xiě):
student = Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
course = Course. objects. all ( ) # 查詢所有課程
student. course. add( * course)
3.2 set
set接收一個(gè)List,List里面的元素為Model對(duì)象,用于多條記錄的多對(duì)多關(guān)系建立 (如果已經(jīng)存在了多對(duì)多關(guān)系,則會(huì)刪除原來(lái)的關(guān)系,重新進(jìn)行建立) :
student = Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
course = Course. objects. all ( ) # 查詢所有課程
student. course. set ( course)
3. 刪除多對(duì)多數(shù)據(jù)及關(guān)系
1)僅刪除關(guān)系
1.1 刪除單個(gè)關(guān)系
student = Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
course= student. course. get( id = 7 )
student. course. remove( course)
1.2 刪除部分關(guān)系
student = Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
course = student. course. filter ( id__in= [ 6 , 7 ] )
student. course. remove( * course)
1.3 刪除所有關(guān)系
student = Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
student. course. clear( )
2)刪除關(guān)系并刪除數(shù)據(jù)
2.1 刪除單個(gè)
student = Student. objects. get( id = 1 ) # 先通過(guò)學(xué)生id找到曲鳥(niǎo)這個(gè)學(xué)生
student. course. filter ( id = 6 ) . delete( )
2.2 刪除部分
student. course. filter ( id__in= [ 6 , 7 ] ) . delete( )
2.3 刪除所有
student. course. all ( ) . delete( )
4. 修改多對(duì)多數(shù)據(jù)及關(guān)系
可以通過(guò)上面講的新增關(guān)系和刪除關(guān)系相結(jié)合進(jìn)行修改的操作,。
5. 查詢多對(duì)多數(shù)據(jù)及關(guān)系
1. 正向查詢
查詢所有
student. course. all ( )
因?yàn)樗褪莔odel對(duì)象,所以所有model使用的ORM關(guān)鍵字都可以使用例如:filter、values等,這里不再舉例,。
2. 反向查詢
例如想通過(guò)課程去查有哪些學(xué)生選修了,在查詢時(shí)加入set關(guān)鍵字即可:
course= Course. objects. get( id = 1 )
data= course. student_set. all ( ) #加入set關(guān)鍵字
print ( data)
輸出結(jié)果
< QuerySet [ < Student: Student object ( 1 ) > ] >
注:對(duì)于上面講的增加,、修改,、刪除中,也同樣可以使用反向查詢進(jìn)行操作