今天,小叮當(dāng)來繼續(xù)為大家分享Django的干貨~

主要內(nèi)容有:表的級聯(lián)刪除、表關(guān)聯(lián)對象的訪問、表關(guān)聯(lián)對象的補(bǔ)充、關(guān)系表的數(shù)據(jù)操作和多表查詢。
首先,我們接著昨天所建的項(xiàng)目db_test,為其配置路由
(1)為db_test新建urls.py文件

(2)在主路由中為db_test分配子路由

(3)設(shè)置db_test的views.py定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
from?django.shortcuts?import?render
#?Create?your?views?here.
from?django.http?import?HttpResponse
#導(dǎo)入學(xué)院表、學(xué)生表、學(xué)生詳細(xì)信息表、課程表
from?.models?import?Department,Student,Stu_detail,Course
def?test(request):
Department.objects.create(d_name='計(jì)算機(jī)')
Department.objects.create(d_name='音樂')
Department.objects.create(d_name='藝術(shù)')
Department.objects.create(d_name='金融')
Department.objects.create(d_name='英語')
Student.objects.create(s_name='小叮當(dāng)',department_id=1)
Student.objects.create(s_name='少年叮當(dāng)',?department_id=2)
Student.objects.create(s_name='青年叮當(dāng)',?department_id=3)
Student.objects.create(s_name='任性叮當(dāng)',?department_id=4)
Student.objects.create(s_name='國外叮當(dāng)',?department_id=5)
return?HttpResponse('小叮當(dāng)在往學(xué)院表和學(xué)生表里建數(shù)據(jù)')
(4)在db_test的urls.py中配置對應(yīng)的路由
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
from?django.urls?import?path
from?.?import?views
urlpatterns?=?[
path('test/',views.test),
]
(5)在瀏覽器中訪問

(6)通過xshell進(jìn)行查看


可以看到,學(xué)院表和學(xué)生表已成功創(chuàng)建。
一、表的級聯(lián)刪除
(1)在主表中刪除數(shù)據(jù),對應(yīng)表中的數(shù)據(jù)也會被刪除。
例如,將學(xué)院表中的計(jì)算機(jī)學(xué)院刪除,對應(yīng)學(xué)生表中屬于計(jì)算機(jī)學(xué)院的小叮當(dāng)則也會被刪除。
重新定義db_test中views.py里的視圖函數(shù)test
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
from?django.shortcuts?import?render
#?Create?your?views?here.
from?django.http?import?HttpResponse
#導(dǎo)入學(xué)院表、學(xué)生表、學(xué)生詳細(xì)信息表、課程表
from?.models?import?Department,Student,Stu_detail,Course
def?test(request):
Department.objects.get(d_id=1).delete()
return?HttpResponse('小叮當(dāng)將學(xué)院表中id=1的學(xué)院刪除了')
在瀏覽器中訪問,使視圖函數(shù)運(yùn)行

通過xshell查看數(shù)據(jù)庫

可見計(jì)算機(jī)學(xué)院從學(xué)院表中刪除后,與之關(guān)聯(lián)的學(xué)生表中的小叮當(dāng)也被刪除了。
(2)設(shè)置默認(rèn)值為空的級聯(lián)刪除
當(dāng)我們進(jìn)行級聯(lián)刪除時(shí),只想刪除主表中的數(shù)據(jù)以及其他表對它的引用,而不刪除其他表中的數(shù)據(jù)時(shí),該怎么做呢?
例如,我想刪除學(xué)院表中id=2的音樂學(xué)院和學(xué)生表中對音樂學(xué)院的引用,而不刪除學(xué)生表中的少年叮當(dāng)
首先,我們可以在xshell中進(jìn)入mysql
執(zhí)行 show create table db_test_student\G?查看創(chuàng)建db_test_student表的mysql語句?"\G"表示結(jié)果按列輸出

可以看到,department_id不允許為空
我們在models.py中更改表結(jié)構(gòu),將學(xué)生信息表中的on_delete其設(shè)置為默認(rèn)值為空的級聯(lián)刪除

具體代碼如下:
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
#2.創(chuàng)建學(xué)生信息表
class?Student(models.Model):
s_id?=?models.AutoField(primary_key=True)
s_name?=?models.CharField(max_length=30)
#實(shí)現(xiàn)一對多關(guān)系ForeignKey?其中on_delete使用默認(rèn)值為空的級聯(lián)刪除
department?=?models.ForeignKey('Department',on_delete=models.SET_NULL,null=True)
(當(dāng)然,如果不想執(zhí)行級聯(lián)刪除,可以on_delete=models.PROTECT 將其保護(hù)起來)
更改表結(jié)構(gòu)后,執(zhí)行映射等操作。
在Tools中找到Run manage.py Task...

執(zhí)行makemigrations

執(zhí)行migrate

之后在xhell的mysql中再次查看表結(jié)構(gòu),發(fā)現(xiàn)department_id字段已默認(rèn)為空

重新定義db_test中views.py里的視圖函數(shù)test
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
from?django.shortcuts?import?render
#?Create?your?views?here.
from?django.http?import?HttpResponse
#導(dǎo)入學(xué)院表、學(xué)生表、學(xué)生詳細(xì)信息表、課程表
from?.models?import?Department,Student,Stu_detail,Course
def?test(request):
Department.objects.get(d_id=2).delete()
return?HttpResponse('小叮當(dāng)將學(xué)院表中id=2的學(xué)院刪除了')
在瀏覽器中訪問

通過xshell查看數(shù)據(jù)庫

二、表關(guān)聯(lián)對象的訪問
1.一對多關(guān)聯(lián)?學(xué)院表和學(xué)生表
(1)在models.py中重新定義模型類,為學(xué)院表和學(xué)生表加上自定義輸出def __str__(self)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
#1.創(chuàng)建學(xué)院信息表
class?Department(models.Model):
d_id?=?models.AutoField(primary_key=True)
d_name?=?models.CharField(max_length=30)
def?__str__(self):
return?'Department'?%?(self.d_id,self.d_name)
#2.創(chuàng)建學(xué)生信息表
class?Student(models.Model):
s_id?=?models.AutoField(primary_key=True)
s_name?=?models.CharField(max_length=30)
#實(shí)現(xiàn)一對多關(guān)系ForeignKey?其中on_delete為必填字段使用級聯(lián)刪除CASCADE
department?=?models.ForeignKey('Department',on_delete=models.CASCADE,null=True)
def?__str__(self):
return?'Students'%(self.s_id,self.s_name,self.department_id)
(2)重新定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
d1?=?Department.objects.get(d_id=3)?#一個(gè)學(xué)院類的實(shí)例對象
s1?=?Student.objects.get(s_id=3)#一個(gè)學(xué)生類的實(shí)例對象
print(s1.department,type(s1.department))#學(xué)生所屬學(xué)院
print(s1.department.d_name)#學(xué)生所屬學(xué)院的名稱
stu=d1.student_set.all()?#學(xué)院里所屬的學(xué)生(反向查詢)
print(stu)
return?HttpResponse('小叮當(dāng)在進(jìn)行表關(guān)聯(lián)對象的訪問')
(3)在瀏覽器中訪問

(4)在后臺查看輸出

小結(jié):在學(xué)生表查詢到的學(xué)生信息相當(dāng)于學(xué)生類的實(shí)例對象,可以直接像訪問成員函數(shù)那樣訪問學(xué)院類中的屬性,以此來實(shí)現(xiàn)表關(guān)聯(lián)對象的訪問。
值得注意,學(xué)生表關(guān)聯(lián)了學(xué)院表,想查詢學(xué)院有哪些學(xué)生時(shí)就屬于反向查詢了。
反向查詢
(1)直接反向查詢
直接反向查詢,是通過查詢關(guān)鍵字加”_set"來實(shí)現(xiàn)的,例如“student_set",如果表關(guān)系是一對一,則不加_set也可。
(2)重命名查詢?related_name
通過在模型類中添加related_name的方法,也可進(jìn)行反向查詢

具體代碼如下
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
#2.創(chuàng)建學(xué)生信息表
class?Student(models.Model):
s_id?=?models.AutoField(primary_key=True)
s_name?=?models.CharField(max_length=30)
#實(shí)現(xiàn)一對多關(guān)系ForeignKey?其中on_delete為必填字段使用級聯(lián)刪除CASCADE
department?=?models.ForeignKey('Department',on_delete=models.CASCADE,related_name='students')
def?__str__(self):
return?'Students'%(self.s_id,self.s_name,self.department_id)
此時(shí)進(jìn)行反向查詢時(shí),使用students即可。因?yàn)橄到y(tǒng)中已經(jīng)沒有了student_set屬性,若還按student_set查詢則會報(bào)錯(cuò)

在視圖函數(shù)中改為用students查詢,即可成功查詢

2.一對一關(guān)聯(lián)?學(xué)生表和學(xué)生詳細(xì)表
(1)查看學(xué)生信息詳細(xì)表?和學(xué)生表?


(2)models.py中在學(xué)生詳細(xì)模型類中自定義輸出?def__str__(self)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
#4.學(xué)生詳細(xì)信息表
class?Stu_detail(models.Model):
#?實(shí)現(xiàn)一對一關(guān)系OneToOneField?其中on_delete為必填字段使用級聯(lián)刪除CASCADE
student?=?models.OneToOneField('Student',on_delete=models.CASCADE)
age?=?models.IntegerField()
gender?=?models.BooleanField(default=1)
city?=?models.CharField(max_length=30,null=True)
def?__str__(self):
return?'Stu_detail'%(self.student_id,self.age,self.gender,self.city)
(3)views.py中根據(jù)表字段創(chuàng)建數(shù)據(jù)表
由于學(xué)生詳細(xì)信息表關(guān)聯(lián)的是學(xué)生表,所以在創(chuàng)建學(xué)生詳細(xì)表時(shí),id要從學(xué)生表里現(xiàn)在有的”2、3、4、5“中創(chuàng)建。
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
from?django.shortcuts?import?render
#?Create?your?views?here.
from?django.http?import?HttpResponse
#導(dǎo)入學(xué)院表、學(xué)生表、學(xué)生詳細(xì)信息表、課程表
from?.models?import?Department,Student,Stu_detail,Course
def?test(request):
Stu_detail.objects.create(age=18,gender=0,city='洛陽',student_id=3)
return?HttpResponse('小叮當(dāng)在創(chuàng)建學(xué)生詳細(xì)信息表')
在瀏覽器中訪問觸發(fā)視圖函數(shù)

在數(shù)據(jù)庫中查看

(4)重新定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
from?django.shortcuts?import?render
#?Create?your?views?here.
from?django.http?import?HttpResponse
#導(dǎo)入學(xué)院表、學(xué)生表、學(xué)生詳細(xì)信息表、課程表
from?.models?import?Department,Student,Stu_detail,Course
def?test(request):
std?=?Stu_detail.objects.get(id=1)?#一個(gè)學(xué)生的詳細(xì)信息
print(std.student.s_name)?#正向查詢
print(s1.stu_detail)?#反向查,直接類名小寫
return?HttpResponse('小叮當(dāng)在實(shí)現(xiàn)一對一表關(guān)系的對象訪問')
(5)在瀏覽器中訪問

(6)在后臺查看

3.多對多關(guān)聯(lián)?學(xué)生表和課程表
(1)查詢課程表字段

根據(jù)字段在views.py中為課程表添加數(shù)據(jù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
from?django.shortcuts?import?render
#?Create?your?views?here.
from?django.http?import?HttpResponse
#導(dǎo)入學(xué)院表、學(xué)生表、學(xué)生詳細(xì)信息表、課程表
from?.models?import?Department,Student,Stu_detail,Course
def?test(request):
Course.objects.create(c_name='Python')
Course.objects.create(c_name='自然語言處理')
Course.objects.create(c_name='養(yǎng)豬')
Course.objects.create(c_name='推塔與補(bǔ)兵')
Course.objects.create(c_name='如何對線')
Course.objects.create(c_name='攝影')
return?HttpResponse('小叮當(dāng)在創(chuàng)建課程表')
在瀏覽器中訪問

在數(shù)據(jù)庫中查看

在models.py中為課程表自定義輸出?def __str__(self)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
#3.課程信息表
class?Course(models.Model):
c_id?=?models.AutoField(primary_key=True)
c_name?=?models.CharField(max_length=30)
student?=?models.ManyToManyField('Student')
def?__str__(self):
return?'Course'%(self.c_id,self.c_name)
由于訪問方法和之前的一樣,這里不再演示,在views.py中定義代碼如下
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
s4?=?Student.objects.get(s_id=4)?#一個(gè)學(xué)生的實(shí)例
c1?=?Course.objects.get(c_id=1)?#一個(gè)課程的實(shí)例
print(c1.student.all())?#正向查詢
#print(s4.course_set.all())?#反向查詢?默認(rèn)的是course_set
print(s4.courses.all())?#related_name?指定名字為courses
三、表關(guān)聯(lián)對象的補(bǔ)充
在表關(guān)聯(lián)中的正向查詢是指,一個(gè)表的模型類可以在另個(gè)一表的模型類中找到。
例如,在課程表的模型類中可以直接訪問到學(xué)生表模型類

那么,查詢一門課程所選的學(xué)生就是正向查詢。反之查詢學(xué)生選了哪些課就是反向查詢。

四、關(guān)系表的數(shù)據(jù)操作
1.數(shù)據(jù)的添加
(1)一對多關(guān)系 add()添加已經(jīng)存在的數(shù)據(jù)? ?create()添加新的數(shù)據(jù)
在views.py中重新定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
d3?=?Department.objects.get(d_id=3)
s3?=?Student.objects.get(s_id=3)
std?=?Stu_detail.objects.get(id=1)
c1?=?Course.objects.get(c_id=1)
sn_xdd?=?Student.objects.get(s_id=2)
#一對多關(guān)系?數(shù)據(jù)的添加?add()?添加的數(shù)據(jù)首先已存在
d3.students.add(sn_xdd)
gw_xdd?=?Student.objects.get(s_id=5)
#如果原有學(xué)生已有所屬學(xué)院?add則可起到修改的作用
#將s_id=5的學(xué)生所屬院改為d_id=3的學(xué)院
d3.students.add(gw_xdd)
#新建數(shù)據(jù)?create()
d3.students.create(s_name='測試小叮當(dāng)1')
d3.students.create(s_name='測試小叮當(dāng)2')
return?HttpResponse('小叮當(dāng)在進(jìn)行一對多關(guān)系表的數(shù)據(jù)添加')
在瀏覽器中訪問觸發(fā)視圖函數(shù)

在數(shù)據(jù)庫中查看

(2)多對多關(guān)系add()添加已經(jīng)存在的數(shù)據(jù)? ?create()添加新的數(shù)據(jù)
在views.py中重新定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
d3?=?Department.objects.get(d_id=3)
s3?=?Student.objects.get(s_id=3)
std?=?Stu_detail.objects.get(id=1)
c1?=?Course.objects.get(c_id=1)
sn_xdd?=?Student.objects.get(s_id=2)
#?#一對多關(guān)系?數(shù)據(jù)的添加?add()?添加的數(shù)據(jù)首先已存在
#?d3.students.add(sn_xdd)
gw_xdd?=?Student.objects.get(s_id=5)
'''多對多'''
c2?=?Course.objects.get(c_id=2)
#添加?3號學(xué)生選了1號和2號課程
s3.courses.add(c1,c2)
#新建?學(xué)院為3號學(xué)生開設(shè)了英雄聯(lián)盟課程
s3.courses.create(c_name='英雄聯(lián)盟')
return?HttpResponse('小叮當(dāng)在進(jìn)行多對多關(guān)系表的數(shù)據(jù)添加')
在瀏覽器中訪問?觸發(fā)視圖函數(shù)

在數(shù)據(jù)庫中查找課程表、課程-學(xué)生中間信息表

2.數(shù)據(jù)刪除?remove()?和clear()
(1)remove()
一對多關(guān)系的表使用remove刪除時(shí),必須保證外鍵列允許為空
例如,學(xué)院表和學(xué)生的對應(yīng)關(guān)系

多對多關(guān)系,使用remove刪除,刪除掉的是中間信息表
在視圖函數(shù)中定義
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
d3?=?Department.objects.get(d_id=3)
s3?=?Student.objects.get(s_id=3)
std?=?Stu_detail.objects.get(id=1)
c1?=?Course.objects.get(c_id=1)
sn_xdd?=?Student.objects.get(s_id=2)
gw_xdd?=?Student.objects.get(s_id=5)
c2?=?Course.objects.get(c_id=2)
d3.students.remove(sn_xdd)
s3.courses.remove(c1,c2)
return?HttpResponse('小叮當(dāng)在使用remove進(jìn)行關(guān)系表的數(shù)據(jù)刪除')
在瀏覽器中訪問

在數(shù)據(jù)庫中查詢

(2)clear()進(jìn)行清空
使用print查看3號學(xué)生選了哪些課程
定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
s3?=?Student.objects.get(s_id=3)
print(s3.courses.all())
return?HttpResponse('小叮當(dāng)在查看3號學(xué)生的選課')
瀏覽器中訪問

后臺中查看

定義視圖函數(shù)使用clear
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
s3?=?Student.objects.get(s_id=3)
print(s3.courses.all())
s3.courses.clear()
return?HttpResponse('小叮當(dāng)使用clear清除了3號學(xué)生的選課')
瀏覽器中訪問

后臺查詢

數(shù)據(jù)庫中查詢中間課程-學(xué)生信息表

可見,clear()會將符合條件的數(shù)據(jù)全部清空0
五、多表查詢
多表查詢又被稱為是跨關(guān)聯(lián)關(guān)系的查詢。
Django 提供一種強(qiáng)大而又直觀的方式來“處理”查詢中的關(guān)聯(lián)關(guān)系,它在后臺自動幫你處理JOIN。 若要跨越關(guān)聯(lián)關(guān)系,只需使用關(guān)聯(lián)的模型字段的名稱,并使用雙下劃線分隔,直至你想要的字段。
1.重建學(xué)生選課數(shù)據(jù)
在views.py中重新定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
d3?=?Department.objects.get(d_id=3)
s3?=?Student.objects.get(s_id=3)
std?=?Stu_detail.objects.get(id=1)
c1?=?Course.objects.get(c_id=1)
sn_xdd?=?Student.objects.get(s_id=2)
#?#一對多關(guān)系?數(shù)據(jù)的添加?add()?添加的數(shù)據(jù)首先已存在
#?d3.students.add(sn_xdd)
gw_xdd?=?Student.objects.get(s_id=5)
'''多對多'''
c2?=?Course.objects.get(c_id=2)
#添加?3號學(xué)生選了1號和2號課程
s3.courses.add(c1,c2)
#新建?學(xué)院為3號學(xué)生開設(shè)了英雄聯(lián)盟課程
s3.courses.create(c_name='英雄聯(lián)盟')
return?HttpResponse('小叮當(dāng)在進(jìn)行選課數(shù)據(jù)的重建')
在瀏覽器中訪問?觸發(fā)視圖函數(shù)

在數(shù)據(jù)庫中查看

2.進(jìn)行多表查詢
在views.py中重新定義視圖函數(shù)
#!/usr/bin/env?python
#?-*-?coding:utf-8?-*-
__author__?=?'IT小叮當(dāng)'
__time__?=?'2019-02-19?15:21'
def?test(request):
#1.查詢學(xué)院名字為'藝術(shù)’的學(xué)生信息
ds?=?Student.objects.filter(department__d_name='藝術(shù)')
print('查詢1',ds)
#2.查詢學(xué)生名字中包含‘測試’的學(xué)生的學(xué)院信息
sd=Department.objects.filter(students__s_name__contains='測試')
print('查詢2',sd)
#3.查詢學(xué)號為3的學(xué)生的所有課程
sc?=?Course.objects.filter(student__s_id=3)
print('查詢3',sc)
#4.查詢報(bào)了課程1的所有學(xué)生的信息
cs?=?Student.objects.filter(courses__c_id=1)
print('查詢4',cs)
#5.查詢報(bào)了python課程的學(xué)生的所屬學(xué)院信息
psd?=?Department.objects.filter(students__courses__c_name=?'python')
print('查詢5',psd)
return?HttpResponse('小叮當(dāng)在進(jìn)行多表查詢')
在瀏覽器中查看

在后臺查看

對照數(shù)據(jù)庫進(jìn)行檢驗(yàn)


經(jīng)檢查查詢結(jié)果正確,可見Django的多表查詢結(jié)果是十分便捷的了。