目錄
- 一 表關(guān)系回顧
- 二 創(chuàng)建模型
- 三 添加、刪除、修改記錄
- 四 查詢記錄
一 表關(guān)系回顧

? 在講解MySQL時(shí),我們提到,把應(yīng)用程序的所有數(shù)據(jù)都放在一張表里是極不合理的。
? 比如我們開(kāi)發(fā)一個(gè)員工管理系統(tǒng),在數(shù)據(jù)庫(kù)里只創(chuàng)建一張員工信息表,該表有四個(gè)字段:工號(hào)、姓名、部門名、部門職能描述,此時(shí)若公司有1萬(wàn)名員工,但只有3個(gè)部門,因?yàn)槊恳幻麊T工后都需要跟著部門信息(部門名、部門職能),所以將會(huì)導(dǎo)致部門信息出現(xiàn)大量重復(fù)、浪費(fèi)空間。

? 解決方法就是將數(shù)據(jù)存放于不同的表中,然后基于foreign key建立表之間的關(guān)聯(lián)關(guān)系。
? 細(xì)說(shuō)的話,表之間存在三種關(guān)系:多對(duì)一、一對(duì)一、多對(duì)多,那如何確定兩張表之間的關(guān)系呢?按照下述步驟操作即可
左表<------------------------------->右表
# 步驟一:先分析
#分析1、先站在左表的角度
是否左表的多條記錄可以對(duì)應(yīng)右表的一條記錄
#分析2、再站在右表的角度去找
是否右表的多條記錄可以對(duì)應(yīng)左表的一條記錄
# 步驟二:后確定關(guān)系
# 多對(duì)一
如果只有"分析1"成立,那么可以確定兩張表的關(guān)系是:左表多對(duì)一右表,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在左表中,然后foreign key 右表一個(gè)字段(通常是id)
如果只有"分析2"成立,那么可以確定兩張表的關(guān)系是:右表多對(duì)一左表,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在右表中,然后foreign key 左表一個(gè)字段(通常是id)
# 一對(duì)一
如果"分析1"和"分析2"都不成立,而是左表的一條記錄唯一對(duì)應(yīng)右表的一條記錄,反之亦然。這種情況很簡(jiǎn)單,就是在左表foreign key右表的基礎(chǔ)上,將左表的關(guān)聯(lián)字段設(shè)置成unique即可
# 多對(duì)多
如果"分析1"和"分析2"同時(shí)成立,則證明這兩張表是一個(gè)雙向的多對(duì)一,即多對(duì)多,需要?jiǎng)?chuàng)建一張單獨(dú)的新表來(lái)專門存放二者的關(guān)系,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在新表中,然后在新表中分別foreign key兩張表的id字段
我們以一個(gè)圖書(shū)管理系統(tǒng)為背景,設(shè)計(jì)了下述四張表,讓我們來(lái)找一找它們之間的關(guān)系
書(shū)籍表:app01_book
出版社表:app01_publish
作者表:app01_author
作者詳細(xì)信息表:app01_authordetail
例1、app01_book與app01_publish
找關(guān)系
左表(app01_book)<------------------------------->右表(app01_publish)
# 步驟一:
#分析1、先站在左表的角度
左表的多條記錄代表多版本書(shū)籍,右表的一條記錄代表一個(gè)出版社,多本書(shū)籍對(duì)應(yīng)同一個(gè)出版社 ??
#分析2、再站在右表的角度去找
右表的多條記錄代表多個(gè)出版社,左表的一條記錄代表一本書(shū),多個(gè)出版社不能出版同一本書(shū) ?
# 步驟二:后確定關(guān)系
# 多對(duì)一
只有"分析1"成立,那么可以確定兩張表的關(guān)系是:左表(app01_book)多對(duì)一右表(app01_publish),關(guān)聯(lián)字段應(yīng)該創(chuàng)建在左表(app01_book)中,然后foreign key 右表(app01_publish)的id字段
sql語(yǔ)句
# 1、由于foreign key的影響,必須先創(chuàng)建被關(guān)聯(lián)表
CREATE TABLE app01_publish (
id INT PRIMARY KEY auto_increment,
name VARCHAR (20)
);
# 2、才能創(chuàng)建出關(guān)聯(lián)表
CREATE TABLE app01_book (
id INT PRIMARY KEY auto_increment,
title VARCHAR (20),
price DECIMAL (8, 2),
pub_date DATE,
publish_id INT, # 新增關(guān)聯(lián)字段
FOREIGN KEY (publish_id) REFERENCES app01_publish (id)
ON UPDATE CASCADE ON DELETE CASCADE
);
例2、app01_author與app01_authordetail
找關(guān)系
左表(app01_author)<------------------------------->右表(app01_authordetail)
一個(gè)作者唯一對(duì)應(yīng)一條自己的詳情信息,反之亦然,所以兩張表是一對(duì)一的關(guān)系。在左表中新增關(guān)聯(lián)字段并添加unique約束,然后foreign key右表
sql語(yǔ)句
# 1、由于foreign key的影響,必須先創(chuàng)建被關(guān)聯(lián)表
CREATE TABLE app01_authordetail (
id INT PRIMARY KEY auto_increment,
tel VARCHAR (20)
);
# 2、才能創(chuàng)建出關(guān)聯(lián)表
CREATE TABLE app01_author (
id INT PRIMARY KEY auto_increment,
name VARCHAR (20),
age INT,
authordetail_id INT UNIQUE, # 新增關(guān)聯(lián)字段,并添加唯一性約束unique
FOREIGN KEY (authordetail_id) REFERENCES app01_authordetail (id)
ON UPDATE CASCADE ON DELETE CASCADE
);
例3、app01_book與app01_author
找關(guān)系
左表(app01_book)<------------------------------->右表(app01_author)
# 步驟一:
#分析1、先站在左表的角度
左表的多條記錄代表多版本書(shū)籍,右表的一條記錄代表一個(gè)作者,多本書(shū)籍可以由同一個(gè)作者編寫 ??
#分析2、再站在右表的角度去找
右表的多條記錄代表多個(gè)作者,左表的一條記錄代表一本書(shū),多個(gè)作者可以合作編寫同一本書(shū) ??
# 步驟二:后確定關(guān)系
# 多對(duì)多
"分析1"和"分析2"同時(shí)成立,證明這兩張表是多對(duì)多的關(guān)系,需要?jiǎng)?chuàng)建一張單獨(dú)的新表來(lái)專門存放二者的關(guān)系,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在新表中,然后在新表中分別foreign key兩張表的id字段
sql語(yǔ)句
# 1、創(chuàng)建被關(guān)聯(lián)表一:app01_book,例1中已創(chuàng)建
# 2、創(chuàng)建被關(guān)聯(lián)表二:app01_author,例2中已創(chuàng)建
# 3、創(chuàng)建新表,存放app01_book于app01_author的關(guān)聯(lián)關(guān)系
CREATE TABLE app01_book_authors (
id INT PRIMARY KEY auto_increment,
book_id INT, # 新增關(guān)聯(lián)字段,用來(lái)關(guān)聯(lián)表app01_book
author_id INT, # 新增關(guān)聯(lián)字段,用來(lái)關(guān)聯(lián)表app01_author
FOREIGN KEY (book_id) REFERENCES app01_book (id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (author_id) REFERENCES app01_author (id) ON UPDATE CASCADE ON DELETE CASCADE
);
上述三個(gè)例子中生成的表如下
鏈接:https://www.processon.com/diagraming/5a895fdde4b0874437c9c580

二 創(chuàng)建模型
模型類如下
from django.db import models
# 表app01_publish
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
# 表app01_book
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=20)
price = models.DecimalField(max_digits=8, decimal_places=2)
pub_date = models.DateField()
# 表app01_book多對(duì)一表app01_publish,參數(shù)to指定模型名,參數(shù)to_field指定要關(guān)聯(lián)的那個(gè)字段
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
# 我們自己寫sql時(shí),針對(duì)書(shū)籍表與作者表的多對(duì)關(guān)系,需要自己創(chuàng)建新表,而基于django的orm,下面這一行代碼可以幫我們自動(dòng)創(chuàng)建那張關(guān)系表
authors=models.ManyToManyField(to='Author')
# 變量名為authors,則新表名為app01_book_authors,若變量名為xxx,則新表名為app01_book_xxx
# 表app01_author
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
age = models.IntegerField()
# 表app01_author一對(duì)一表app01_authordetail
author_detail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE)
# 表app01_authordetail
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
tel = models.CharField(max_length=20)
強(qiáng)調(diào):
在創(chuàng)建關(guān)聯(lián)時(shí),針對(duì)參數(shù)to,如果傳入的是字符串(to="模型名"),則模型類的定義不區(qū)分先后順序,如果傳入的是模型名(to=Author),則Author類必須事先定義

三 添加、刪除、修改記錄
3.1 添加記錄

!!強(qiáng)調(diào)?。。荷蠄D所示的表名、字段名都是mysql中的真實(shí)表/物理表,而我們下述所示所有操作,都是通過(guò)模型類來(lái)操作物理表,例如無(wú)論增刪改查,所使用的字段名都模型類中的字段
按照上圖所示,由于foreign key的關(guān)系,我們需要事先往app01_publish與app01_authordetail里插入記錄
# 1、需求:通過(guò)模型Publish往表app01_publish里插入三家出版社
Publish.objects.create(name='北京出版社')
Publish.objects.create(name='長(zhǎng)春出版社')
Publish.objects.create(name='大連出版社')
# 2、需求:通過(guò)模型AuthorDetail往表app01_authordetail里插入三條作者詳情
AuthorDetail.objects.create(tel='18611312331')
AuthorDetail.objects.create(tel='15033413881')
AuthorDetail.objects.create(tel='13011453220')
按照上圖所示,插入時(shí)會(huì)涉及到多張表,我們同樣分三種情況來(lái)介紹
1、多對(duì)一:app01_book與app01_publish
# 需求:書(shū)籍(葵花寶典、菊花寶典、桃花寶典)都是在北京出版社出版的
# 1、先通過(guò)模型Publish從出版社表app01_publish查出北京出版社
publish_obj=Publish.objects.filter(name='北京出版社').first()
# 上述代碼也可以簡(jiǎn)寫為:publish_obj=Publish.objects.get(name='北京出版社')
# 2、再通過(guò)模型Book往書(shū)籍表app01_book里插入三本書(shū)籍與出版社的對(duì)應(yīng)關(guān)系
# 方式一:使用publish參數(shù)指定關(guān)聯(lián)
book_obj1=Book.objects.create(title='葵花寶典',price=2000,pub_date='1985-3-11',publish=publish_obj)
book_obj2=Book.objects.create(title='菊花寶典',price=3000,pub_date='1990-1-21',publish=publish_obj)
book_obj3=Book.objects.create(title='桃花寶典',price=4000,pub_date='1991-1-23',publish=publish_obj)
# 方式二:使用publish_id參數(shù)指定關(guān)聯(lián)
book_obj1=Book.objects.create(title='葵花寶典',price=2000,pub_date='1985-3-11',publish_id=publish_obj.nid)
book_obj2=Book.objects.create(title='菊花寶典',price=3000,pub_date='1990-1-21',publish_id=1) # 在已經(jīng)出版社id的情況下,可以直接指定
book_obj3=Book.objects.create(title='桃花寶典',price=4000,pub_date='1991-1-23',publish_id=1)
# 注意:無(wú)論方式一還是方式二得到的書(shū)籍對(duì)象book_obj1、book_obj2、book_obj3
# 都可以調(diào)用publish字段來(lái)訪問(wèn)關(guān)聯(lián)的那一個(gè)出版社對(duì)象
# 都可以調(diào)用publish_id來(lái)訪問(wèn)關(guān)聯(lián)的那一個(gè)出版社對(duì)象的nid
print(book_obj1.publish,book_obj1.publish_id)
print(book_obj2.publish,book_obj2.publish_id)
print(book_obj3.publish,book_obj3.publish_id)
# 三本書(shū)關(guān)聯(lián)的是同一個(gè)出版社,所以輸出結(jié)果均相同
參照上述步驟,把剩余三本書(shū)與出版社的對(duì)應(yīng)關(guān)系也插入
book_obj1 = Book.objects.create(title='玉女心經(jīng)', price=5000, pub_date='1988-3-24', publish_id=2)
book_obj2 = Book.objects.create(title='玉男心經(jīng)', price=3000, pub_date='1985-6-17', publish_id=2)
book_obj3 = Book.objects.create(title='九陰真經(jīng)', price=6000, pub_date='1983-8-17', publish_id=3)
2、一對(duì)一:app01_author與app01_authordetail
# 需求:插入三個(gè)作者,并與作者詳情表一一對(duì)應(yīng)
# 由于作者詳情表我們已經(jīng)事先創(chuàng)建好記錄,所以只需要往作者表插入記錄即可
# 方式一:需要事先過(guò)濾出作者詳情的對(duì)象,然后通過(guò)模型Author的字段author來(lái)指定要關(guān)聯(lián)的作者詳情對(duì)象(略)
# 方式二:確定作者詳情對(duì)象的id,然后通過(guò)模型Author通過(guò)字段author_id來(lái)指定關(guān)聯(lián)關(guān)系,
Author.objects.create(name='egon',age=18,author_detail_id=1)
Author.objects.create(name='kevin',age=38,author_detail_id=2)
Author.objects.create(name='rose',age=28,author_detail_id=3)
3、多對(duì)多:app01_book與app01_author
# 我們參照物理表app01_book_authors制定需求,需要?jiǎng)?chuàng)建如下關(guān)系
# 1、葵花寶典的作者為:egon、kevin
# 2、菊花寶典的作者為:egon、kevin、rose
# 3、桃花寶典的作者為:egon、kevin
# 4、玉女心經(jīng)的作者為:kevin、rose
# 5、玉男心經(jīng)的作者為:kevin
# 6、九陰真經(jīng)的作者為:egon、rose
# 需要?jiǎng)?chuàng)建出上述關(guān)系,具體做法如下
# 1、先獲取書(shū)籍對(duì)象
book_obj1=Book.objects.get(title='葵花寶典')
book_obj2=Book.objects.get(title='菊花寶典')
book_obj3=Book.objects.get(title='桃花寶典')
book_obj4=Book.objects.get(title='玉女心經(jīng)')
book_obj5=Book.objects.get(title='玉男心經(jīng)')
book_obj6=Book.objects.get(title='九陰真經(jīng)')
# 2、然后獲取作者對(duì)象
egon=Author.objects.get(name='egon')
kevin=Author.objects.get(name='kevin')
rose=Author.objects.get(name='rose')
# 3、最后依次創(chuàng)建上述關(guān)系:在原生SQL中多對(duì)多關(guān)系涉及到操作第三張關(guān)系表,但是在ORM中我們只需要操作模型類Book下的字段author即可
book_obj1.authors.add(egon,kevin)
book_obj2.authors.add(egon,kevin,rose)
book_obj3.authors.add(egon,kevin)
book_obj4.authors.add(kevin,rose)
book_obj5.authors.add(kevin)
book_obj6.authors.add(egon,rose)
可以通過(guò)書(shū)籍對(duì)象下的authors字段獲取其所關(guān)聯(lián)的所有作者對(duì)象
book_obj1.authors.all() # 返回一個(gè)存有多個(gè)作者的queryset
3.2 刪除、修改記錄

# 1、book_obj.authors.remove() :將某個(gè)特定的對(duì)象從被關(guān)聯(lián)對(duì)象集合中去除
# 從菊花寶典的作者集合中去掉作者rose
rose = Author.objects.get(name='rose')
book_obj2 = Book.objects.get(title='菊花寶典')
book_obj2.authors.remove(rose)
# 2、book_obj.authors.clear():清空被關(guān)聯(lián)對(duì)象集合
# 清空菊花寶典所關(guān)聯(lián)的所有作者
book_obj2 = Book.objects.get(title='菊花寶典')
book_obj2.authors.clear()
# 3、book_obj.authors.set():先清空再重新設(shè)置
# 玉男心經(jīng)的作者原來(lái)為kevin,要求設(shè)置為egon、rose
egon=Author.objects.get(name='egon')
rose=Author.objects.get(name='rose')
book_obj5 = Book.objects.get(title='玉男心經(jīng)')
book_obj5.authors.set([egon,rose]) # 多個(gè)作者對(duì)象放到列表里

四 查詢記錄
數(shù)據(jù)庫(kù)操作最常用的還是查詢操作,在介紹ORM下多表關(guān)聯(lián)查詢時(shí),需要事先記住關(guān)于ORM模型的一個(gè)非常重要的概念:在使用模型類進(jìn)行多表關(guān)聯(lián)查詢時(shí),如果確定兩張表存在關(guān)聯(lián)關(guān)系,那么在選取一個(gè)表作為起始(為了后續(xù)描述方便,我們將其簡(jiǎn)稱為"基表")后,可以跨表引用來(lái)自另外一張中的字段值,這存在正向與反向之分
如果關(guān)聯(lián)字段存在于基表中,稱之為正向查詢,否則,稱之為反向查詢
例如表模Book與Publish,關(guān)聯(lián)字段存在于Book中
# 當(dāng)以Book為基表時(shí),稱之為正向查詢
Book(基表)-------正向---------->Publish
# 當(dāng)以Publish為基表時(shí),稱之為反向查詢
Book<-------反向----------Publish(基表)
使用原生sql進(jìn)行多表關(guān)聯(lián)查詢時(shí)無(wú)非兩種方式:子查詢、join連表查詢,ORM里同樣有兩種查詢方式(嚴(yán)格依賴正向、反向的概念)
4.1 基于對(duì)象的跨表查詢

1、跨兩張表查詢
1.1、一對(duì)一查詢(模型類Author與AuthorDetail)
正向查詢,按關(guān)聯(lián)字段:author_detail
# 需求:查詢作者egon的手機(jī)號(hào)
# 1、先取出作者對(duì)象
egon=Author.objects.filter(name='egon').first()
# 2、正向查詢:根據(jù)作者對(duì)象下的關(guān)聯(lián)字段author_detail取到作者詳情
print(egon.author_detail.tel) # 輸出:18611312331
反向查詢,按模型名(小寫):author
# 需求:查詢手機(jī)號(hào)為'18611312331'的作者名
# 1、先取出作者的詳情對(duì)象
tel=AuthorDetail.objects.filter(tel='18611312331').first()
# 2、反向查詢:根據(jù)小寫的模型名author取到作者對(duì)象
print(tel.author.name) # 輸出:egon
1.2、多對(duì)一查詢(模型類Book與Publish)
正向查詢,按關(guān)聯(lián)字段:publish
# 需求:查詢葵花寶典的出版社名字
# 1、先取書(shū)籍對(duì)象
book_obj=Book.objects.filter(title='葵花寶典').first()
# 2、正向查詢:根據(jù)書(shū)籍對(duì)象下的關(guān)聯(lián)字段publish取到出版社
print(book_obj.publish.name) # 輸出:北京出版社
反向查詢,按模型名(小寫)_set:book_set
# 需求:查詢北京出版社都出版的所有書(shū)籍名字
# 1、先取出出版社對(duì)象
publish_obj=Publish.objects.filter(name='北京出版社').first()
# 2、反向查詢:根據(jù)book_set取到所有的書(shū)籍
book_objs=publish_obj.book_set.all()
print([book_obj.title for book_obj in book_objs]) # 輸出:['葵花寶典', '菊花寶典', '桃花寶典']
1.3、多對(duì)多查詢(模型類Book與Author)
正向查詢,按關(guān)聯(lián)字段,如authors
# 需求:查詢葵花寶典的所有作者
# 1、先取出書(shū)籍對(duì)象
book_obj=Book.objects.filter(title='葵花寶典').first()
# 2、正向查詢:根據(jù)書(shū)籍對(duì)象下的關(guān)聯(lián)字段authors取到所有作者
author_objs=book_obj.authors.all()
print([obj.name for obj in author_objs]) # 輸出:['egon', 'kevin']
反向查詢,按模型名(小寫)_set:如author_set
# 需求:查詢作者rose出版的所有書(shū)籍
# 1、先取出作者對(duì)象
egon=Author.objects.filter(name='rose').first()
# 2、反向查詢:根據(jù)book_set取到作者對(duì)象
book_objs=egon.book_set.all()
print([book_obj.title for book_obj in book_objs]) # 輸出:['玉女心經(jīng)', '九陰真經(jīng)', '玉男心經(jīng)']
2、連續(xù)跨>2張表查詢
連續(xù)跨>2張表的操作的套路與上面的案例都是一樣的
# 需求:查詢葵花寶典的作者們的手機(jī)號(hào)
book_obj=Book.objects.filter(title='葵花寶典').first()
author_objs=book_obj.authors.all()
print([author_obj.author_detail.tel for author_obj in author_objs])
# 輸出:['18611312331', '15033413881']
4.2 基于雙下劃線的跨表查詢
1、跨兩張表查詢
1.1、一對(duì)一查詢(模型類Author與AuthorDetail)
正向查詢,按關(guān)聯(lián)字段+雙下劃線:author_detail__
# 需求:查詢作者egon的手機(jī)號(hào)
# 注意values()中的參數(shù)是:關(guān)聯(lián)字段名__要取的那張被關(guān)聯(lián)表中的字段
res = Author.objects.filter(name='egon').values('author_detail__tel').first()
print(res['author_detail__tel']) # {'author_detail__tel': '18611312331'}
# 注意:基于雙下劃線的跨表查詢會(huì)被django的orm識(shí)別為join操作,所以上述代碼相當(dāng)于如下sql,后續(xù)案例均是相同原理,我們不再累述
select app01_authordetail.tel from app01_author inner join app01_authordetail on app01_author.author_detail_id = app01_authordetail.nid where app01_author.name = 'egon';
反向查詢,按模型名(小寫)+雙下劃線:author__
# 需求:查詢手機(jī)號(hào)為'18611312331'的作者名
# 注意values()中的參數(shù)是:小寫的模型名__要取的那張被關(guān)聯(lián)表中的字段
res=AuthorDetail.objects.filter(tel='18611312331').values('author__name').first()
print(res) # {'author__name': 'egon'}
補(bǔ)充:基表決定了正向還是反向
# 1、針對(duì)上例中正向查詢的需求:查詢作者egon的手機(jī)號(hào),如果我們選取的基表是AuthorDetail,那么就成了反向查詢,應(yīng)該用反向查詢的語(yǔ)法
res = AuthorDetail.objects.filter(author__name='egon').values('tel').first()
print(res) # {'tel': '18611312331'}
# 2、針對(duì)上例中反向查詢的需求:查詢手機(jī)號(hào)為'18611312331'的作者名,如果我們選取的基表是Author,那么就成了正向查詢,應(yīng)該用正向查詢的語(yǔ)法
res=Author.objects.filter(author_detail__tel='18611312331').values('name').first()
print(res) # {'name': 'egon'}
1.2、多對(duì)一查詢(模型類Book與Publish)
正向查詢,按關(guān)聯(lián)字段+雙下劃線:publish__
# 需求:查詢葵花寶典的出版社名字
# 注意values()中的參數(shù)是:關(guān)聯(lián)字段名__要取的那張被關(guān)聯(lián)表中的字段
res=Book.objects.filter(title='葵花寶典').values('publish__name').first()
print(res['publish__name']) # {'publish__name': '北京出版社'}
反向查詢,按模型名(小寫)+雙下劃線:book__
# 需求:查詢北京出版社都出版的所有書(shū)籍名字
# 注意values()中的參數(shù)是:小寫的模型名__要取的那張被關(guān)聯(lián)表中的字段
res = Publish.objects.filter(name='北京出版社').values('book__title')
print(res) # <QuerySet [{'book__title': '葵花寶典'}, {'book__title': '菊花寶典'}, {'book__title': '桃花寶典'}]>
補(bǔ)充:基表決定了正向還是反向
# 1、針對(duì)上例中正向查詢的需求:查詢葵花寶典的出版社名字,如果我們選取的基表是Publish,那么就成了反向查詢,應(yīng)該用反向查詢的語(yǔ)法
res = Publish.objects.filter(book__title='葵花寶典').values('name').first()
print(res) # {'name': '北京出版社'}
# 2、針對(duì)上例中反向查詢的需求:查詢北京出版社都出版的所有書(shū)籍名字,如果我們選取的基表是Book,那么就成了正向查詢,應(yīng)該用正向查詢的語(yǔ)法
res=Book.objects.filter(publish__name='北京出版社').values('title')
print(res) # <QuerySet [{'title': '葵花寶典'}, {'title': '菊花寶典'}, {'title': '桃花寶典'}]>
1.3、多對(duì)多查詢(模型類Book與Author)
正向查詢,按關(guān)聯(lián)字段+雙下劃線:authors__
# 需求:查詢葵花寶典的所有作者
# 注意values()中的參數(shù)是:關(guān)聯(lián)字段名__要取的那張被關(guān)聯(lián)表中的字段
res=Book.objects.filter(title='葵花寶典').values('authors__name')
print(res) # <QuerySet [{'authors__name': 'egon'}, {'authors__name': 'kevin'}]>
反向查詢,按模型名(小寫)+雙下劃線:如book__
# 需求:查詢作者rose出版的所有書(shū)籍
# 注意values()中的參數(shù)是:小寫的模型名__要取的那張被關(guān)聯(lián)表中的字段
res = Author.objects.filter(name='rose').values('book__title')
print(res) # <QuerySet [{'book__title': '玉女心經(jīng)'}, {'book__title': '九陰真經(jīng)'}, {'book__title': '玉男心經(jīng)'}]>
補(bǔ)充:基表決定了正向還是反向
# 1、針對(duì)上例中正向查詢的需求:查詢葵花寶典的所有作者,如果我們選取的基表是authors,那么就成了反向查詢,應(yīng)該用反向查詢的語(yǔ)法
res=Author.objects.filter(book__title='葵花寶典').values('name')
print(res) # <QuerySet [{'name': 'egon'}, {'name': 'kevin'}]>
# 2、針對(duì)上例中反向查詢的需求:查詢作者rose出版的所有書(shū)籍,如果我們選取的基表是Book,那么就成了正向查詢,應(yīng)該用正向查詢的語(yǔ)法
res=Book.objects.filter(authors__name='rose').values('title')
print(res) # <QuerySet [{'title': '玉女心經(jīng)'}, {'title': '九陰真經(jīng)'}, {'title': '玉男心經(jīng)'}]>
2、連續(xù)跨>2張表查詢
連續(xù)跨>2張表的操作的套路與上面的案例都是一樣的,可以連續(xù)接n個(gè)雙下劃線,只需要在每次連雙下劃線時(shí),確定是正向還是反向即可
# 需求1:查詢北京出版社出版過(guò)的所有書(shū)籍的名字以及作者的姓名、手機(jī)號(hào)
# 方式一:基表為Publish
res=Publish.objects.filter(name='北京出版社').values_list('book__title','book__authors__name','book__authors__author_detail__tel')
# 方式二:基表為Book
res=Book.objects.filter(publish__name='北京出版社').values_list('title','authors__name','authors__author_detail__tel')
# 循環(huán)打印結(jié)果均為
for obj in res:
print(obj)
'''
輸出:
('葵花寶典', 'egon', '18611312331')
('菊花寶典', 'egon', '18611312331')
('桃花寶典', 'egon', '18611312331')
('葵花寶典', 'kevin', '15033413881')
('菊花寶典', 'kevin', '15033413881')
('桃花寶典', 'kevin', '15033413881')
('菊花寶典', 'rose', '13011453220')
'''
# 需求2:查詢手機(jī)號(hào)以186開(kāi)頭的作者出版過(guò)的所有書(shū)籍名稱以及出版社名稱
# 方式一:基表為AuthorDetail
res=AuthorDetail.objects.filter(tel__startswith='186').values_list('author__book__title','author__book__publish__name')
# 方式二:基表為Book
res=Book.objects.filter(authors__author_detail__tel__startswith='186').values_list('title','publish__name')
# 方式三:基表為Publish
res=Publish.objects.filter(book__authors__author_detail__tel__startswith='186').values_list('book__title','name')
# 循環(huán)打印結(jié)果均為
for obj in res:
print(obj)
'''
輸出:
('葵花寶典', '北京出版社')
('菊花寶典', '北京出版社')
('桃花寶典', '北京出版社')
('九陰真經(jīng)', '大連出版社')
'''

加qq群830644110獲取更多高級(jí)文章&項(xiàng)目源代碼
