目錄
- 一 表關(guān)系回顧
- 二 創(chuàng)建模型
- 三 添加百姓、刪除、修改記錄
- 四 查詢記錄
一 表關(guān)系回顧
? 在講解MySQL時巷帝,我們提到往湿,把應(yīng)用程序的所有數(shù)據(jù)都放在一張表里是極不合理的。
? 比如我們開發(fā)一個員工管理系統(tǒng)喻括,在數(shù)據(jù)庫里只創(chuàng)建一張員工信息表邀杏,該表有四個字段:工號、姓名唬血、部門名望蜡、部門職能描述,此時若公司有1萬名員工拷恨,但只有3個部門脖律,因為每一名員工后都需要跟著部門信息(部門名、部門職能)腕侄,所以將會導(dǎo)致部門信息出現(xiàn)大量重復(fù)小泉、浪費(fèi)空間芦疏。
? 解決方法就是將數(shù)據(jù)存放于不同的表中,然后基于foreign key建立表之間的關(guān)聯(lián)關(guān)系微姊。
? 細(xì)說的話酸茴,表之間存在三種關(guān)系:多對一、一對一兢交、多對多薪捍,那如何確定兩張表之間的關(guān)系呢?按照下述步驟操作即可
左表<------------------------------->右表
# 步驟一:先分析
#分析1配喳、先站在左表的角度
是否左表的多條記錄可以對應(yīng)右表的一條記錄
#分析2酪穿、再站在右表的角度去找
是否右表的多條記錄可以對應(yīng)左表的一條記錄
# 步驟二:后確定關(guān)系
# 多對一
如果只有"分析1"成立,那么可以確定兩張表的關(guān)系是:左表多對一右表界逛,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在左表中昆稿,然后foreign key 右表一個字段(通常是id)
如果只有"分析2"成立,那么可以確定兩張表的關(guān)系是:右表多對一左表息拜,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在右表中溉潭,然后foreign key 左表一個字段(通常是id)
# 一對一
如果"分析1"和"分析2"都不成立,而是左表的一條記錄唯一對應(yīng)右表的一條記錄少欺,反之亦然喳瓣。這種情況很簡單,就是在左表foreign key右表的基礎(chǔ)上赞别,將左表的關(guān)聯(lián)字段設(shè)置成unique即可
# 多對多
如果"分析1"和"分析2"同時成立畏陕,則證明這兩張表是一個雙向的多對一,即多對多,需要創(chuàng)建一張單獨(dú)的新表來專門存放二者的關(guān)系仿滔,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在新表中惠毁,然后在新表中分別foreign key兩張表的id字段
我們以一個圖書管理系統(tǒng)為背景,設(shè)計了下述四張表崎页,讓我們來找一找它們之間的關(guān)系
書籍表:app01_book
出版社表:app01_publish
作者表:app01_author
作者詳細(xì)信息表:app01_authordetail
例1鞠绰、app01_book與app01_publish
找關(guān)系
左表(app01_book)<------------------------------->右表(app01_publish)
# 步驟一:
#分析1、先站在左表的角度
左表的多條記錄代表多版本書籍飒焦,右表的一條記錄代表一個出版社蜈膨,多本書籍對應(yīng)同一個出版社 ??
#分析2、再站在右表的角度去找
右表的多條記錄代表多個出版社牺荠,左表的一條記錄代表一本書翁巍,多個出版社不能出版同一本書 ?
# 步驟二:后確定關(guān)系
# 多對一
只有"分析1"成立,那么可以確定兩張表的關(guān)系是:左表(app01_book)多對一右表(app01_publish)休雌,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在左表(app01_book)中灶壶,然后foreign key 右表(app01_publish)的id字段
sql語句
# 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)
一個作者唯一對應(yīng)一條自己的詳情信息孝情,反之亦然,所以兩張表是一對一的關(guān)系洒嗤。在左表中新增關(guān)聯(lián)字段并添加unique約束箫荡,然后foreign key右表
sql語句
# 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、先站在左表的角度
左表的多條記錄代表多版本書籍间唉,右表的一條記錄代表一個作者绞灼,多本書籍可以由同一個作者編寫 ??
#分析2、再站在右表的角度去找
右表的多條記錄代表多個作者呈野,左表的一條記錄代表一本書低矮,多個作者可以合作編寫同一本書 ??
# 步驟二:后確定關(guān)系
# 多對多
"分析1"和"分析2"同時成立,證明這兩張表是多對多的關(guān)系,需要創(chuàng)建一張單獨(dú)的新表來專門存放二者的關(guān)系被冒,關(guān)聯(lián)字段應(yīng)該創(chuàng)建在新表中军掂,然后在新表中分別foreign key兩張表的id字段
sql語句
# 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)字段,用來關(guān)聯(lián)表app01_book
author_id INT, # 新增關(guān)聯(lián)字段葱蝗,用來關(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
);
上述三個例子中生成的表如下
鏈接: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多對一表app01_publish穴张,參數(shù)to指定模型名,參數(shù)to_field指定要關(guān)聯(lián)的那個字段
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
# 我們自己寫sql時两曼,針對書籍表與作者表的多對關(guān)系皂甘,需要自己創(chuàng)建新表,而基于django的orm合愈,下面這一行代碼可以幫我們自動創(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一對一表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ù)to彪蓬,如果傳入的是字符串(to="模型名")寸莫,則模型類的定義不區(qū)分先后順序,如果傳入的是模型名(to=Author)档冬,則Author類必須事先定義
三 添加膘茎、刪除桃纯、修改記錄
3.1 添加記錄
!披坏!強(qiáng)調(diào)L埂!:上圖所示的表名棒拂、字段名都是mysql中的真實表/物理表伞梯,而我們下述所示所有操作,都是通過模型類來操作物理表帚屉,例如無論增刪改查谜诫,所使用的字段名都模型類中的字段
按照上圖所示,由于foreign key的關(guān)系攻旦,我們需要事先往app01_publish與app01_authordetail里插入記錄
# 1喻旷、需求:通過模型Publish往表app01_publish里插入三家出版社
Publish.objects.create(name='北京出版社')
Publish.objects.create(name='長春出版社')
Publish.objects.create(name='大連出版社')
# 2、需求:通過模型AuthorDetail往表app01_authordetail里插入三條作者詳情
AuthorDetail.objects.create(tel='18611312331')
AuthorDetail.objects.create(tel='15033413881')
AuthorDetail.objects.create(tel='13011453220')
按照上圖所示牢屋,插入時會涉及到多張表且预,我們同樣分三種情況來介紹
1、多對一:app01_book與app01_publish
# 需求:書籍(葵花寶典伟阔、菊花寶典辣之、桃花寶典)都是在北京出版社出版的
# 1、先通過模型Publish從出版社表app01_publish查出北京出版社
publish_obj=Publish.objects.filter(name='北京出版社').first()
# 上述代碼也可以簡寫為:publish_obj=Publish.objects.get(name='北京出版社')
# 2皱炉、再通過模型Book往書籍表app01_book里插入三本書籍與出版社的對應(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)
# 注意:無論方式一還是方式二得到的書籍對象book_obj1、book_obj2合搅、book_obj3
# 都可以調(diào)用publish字段來訪問關(guān)聯(lián)的那一個出版社對象
# 都可以調(diào)用publish_id來訪問關(guān)聯(lián)的那一個出版社對象的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)
# 三本書關(guān)聯(lián)的是同一個出版社多搀,所以輸出結(jié)果均相同
參照上述步驟,把剩余三本書與出版社的對應(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灾部、一對一:app01_author與app01_authordetail
# 需求:插入三個作者康铭,并與作者詳情表一一對應(yīng)
# 由于作者詳情表我們已經(jīng)事先創(chuàng)建好記錄,所以只需要往作者表插入記錄即可
# 方式一:需要事先過濾出作者詳情的對象赌髓,然后通過模型Author的字段author來指定要關(guān)聯(lián)的作者詳情對象(略)
# 方式二:確定作者詳情對象的id从藤,然后通過模型Author通過字段author_id來指定關(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锁蠕、多對多:app01_book與app01_author
# 我們參照物理表app01_book_authors制定需求夷野,需要創(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
# 需要創(chuàng)建出上述關(guān)系框沟,具體做法如下
# 1、先獲取書籍對象
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增炭、然后獲取作者對象
egon=Author.objects.get(name='egon')
kevin=Author.objects.get(name='kevin')
rose=Author.objects.get(name='rose')
# 3忍燥、最后依次創(chuàng)建上述關(guān)系:在原生SQL中多對多關(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)
可以通過書籍對象下的authors字段獲取其所關(guān)聯(lián)的所有作者對象
book_obj1.authors.all() # 返回一個存有多個作者的queryset
3.2 刪除隙姿、修改記錄
# 1梅垄、book_obj.authors.remove() :將某個特定的對象從被關(guān)聯(lián)對象集合中去除
# 從菊花寶典的作者集合中去掉作者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)對象集合
# 清空菊花寶典所關(guān)聯(lián)的所有作者
book_obj2 = Book.objects.get(title='菊花寶典')
book_obj2.authors.clear()
# 3输玷、book_obj.authors.set():先清空再重新設(shè)置
# 玉男心經(jīng)的作者原來為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]) # 多個作者對象放到列表里
四 查詢記錄
數(shù)據(jù)庫操作最常用的還是查詢操作欲鹏,在介紹ORM下多表關(guān)聯(lián)查詢時机久,需要事先記住關(guān)于ORM模型的一個非常重要的概念:在使用模型類進(jìn)行多表關(guān)聯(lián)查詢時,如果確定兩張表存在關(guān)聯(lián)關(guān)系赔嚎,那么在選取一個表作為起始(為了后續(xù)描述方便膘盖,我們將其簡稱為"基表")后,可以跨表引用來自另外一張中的字段值尤误,這存在正向與反向之分
如果關(guān)聯(lián)字段存在于基表中侠畔,稱之為正向查詢,否則损晤,稱之為反向查詢
例如表模Book與Publish软棺,關(guān)聯(lián)字段存在于Book中
# 當(dāng)以Book為基表時,稱之為正向查詢
Book(基表)-------正向---------->Publish
# 當(dāng)以Publish為基表時尤勋,稱之為反向查詢
Book<-------反向----------Publish(基表)
使用原生sql進(jìn)行多表關(guān)聯(lián)查詢時無非兩種方式:子查詢喘落、join連表查詢,ORM里同樣有兩種查詢方式(嚴(yán)格依賴正向最冰、反向的概念)
4.1 基于對象的跨表查詢
1瘦棋、跨兩張表查詢
1.1、一對一查詢(模型類Author與AuthorDetail)
正向查詢锌奴,按關(guān)聯(lián)字段:author_detail
# 需求:查詢作者egon的手機(jī)號
# 1兽狭、先取出作者對象
egon=Author.objects.filter(name='egon').first()
# 2憾股、正向查詢:根據(jù)作者對象下的關(guān)聯(lián)字段author_detail取到作者詳情
print(egon.author_detail.tel) # 輸出:18611312331
反向查詢鹿蜀,按模型名(小寫):author
# 需求:查詢手機(jī)號為'18611312331'的作者名
# 1箕慧、先取出作者的詳情對象
tel=AuthorDetail.objects.filter(tel='18611312331').first()
# 2、反向查詢:根據(jù)小寫的模型名author取到作者對象
print(tel.author.name) # 輸出:egon
1.2茴恰、多對一查詢(模型類Book與Publish)
正向查詢颠焦,按關(guān)聯(lián)字段:publish
# 需求:查詢葵花寶典的出版社名字
# 1、先取書籍對象
book_obj=Book.objects.filter(title='葵花寶典').first()
# 2往枣、正向查詢:根據(jù)書籍對象下的關(guān)聯(lián)字段publish取到出版社
print(book_obj.publish.name) # 輸出:北京出版社
反向查詢伐庭,按模型名(小寫)_set:book_set
# 需求:查詢北京出版社都出版的所有書籍名字
# 1、先取出出版社對象
publish_obj=Publish.objects.filter(name='北京出版社').first()
# 2分冈、反向查詢:根據(jù)book_set取到所有的書籍
book_objs=publish_obj.book_set.all()
print([book_obj.title for book_obj in book_objs]) # 輸出:['葵花寶典', '菊花寶典', '桃花寶典']
1.3圾另、多對多查詢(模型類Book與Author)
正向查詢,按關(guān)聯(lián)字段雕沉,如authors
# 需求:查詢葵花寶典的所有作者
# 1集乔、先取出書籍對象
book_obj=Book.objects.filter(title='葵花寶典').first()
# 2、正向查詢:根據(jù)書籍對象下的關(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出版的所有書籍
# 1扰路、先取出作者對象
egon=Author.objects.filter(name='rose').first()
# 2、反向查詢:根據(jù)book_set取到作者對象
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ī)號
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、一對一查詢(模型類Author與AuthorDetail)
正向查詢丈攒,按關(guān)聯(lián)字段+雙下劃線:author_detail__
# 需求:查詢作者egon的手機(jī)號
# 注意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'}
# 注意:基于雙下劃線的跨表查詢會被django的orm識別為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ī)號為'18611312331'的作者名
# 注意values()中的參數(shù)是:小寫的模型名__要取的那張被關(guān)聯(lián)表中的字段
res=AuthorDetail.objects.filter(tel='18611312331').values('author__name').first()
print(res) # {'author__name': 'egon'}
補(bǔ)充:基表決定了正向還是反向
# 1、針對上例中正向查詢的需求:查詢作者egon的手機(jī)號深碱,如果我們選取的基表是AuthorDetail腹鹉,那么就成了反向查詢,應(yīng)該用反向查詢的語法
res = AuthorDetail.objects.filter(author__name='egon').values('tel').first()
print(res) # {'tel': '18611312331'}
# 2敷硅、針對上例中反向查詢的需求:查詢手機(jī)號為'18611312331'的作者名功咒,如果我們選取的基表是Author,那么就成了正向查詢绞蹦,應(yīng)該用正向查詢的語法
res=Author.objects.filter(author_detail__tel='18611312331').values('name').first()
print(res) # {'name': 'egon'}
1.2力奋、多對一查詢(模型類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__
# 需求:查詢北京出版社都出版的所有書籍名字
# 注意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景殷、針對上例中正向查詢的需求:查詢葵花寶典的出版社名字,如果我們選取的基表是Publish,那么就成了反向查詢猿挚,應(yīng)該用反向查詢的語法
res = Publish.objects.filter(book__title='葵花寶典').values('name').first()
print(res) # {'name': '北京出版社'}
# 2咐旧、針對上例中反向查詢的需求:查詢北京出版社都出版的所有書籍名字,如果我們選取的基表是Book绩蜻,那么就成了正向查詢铣墨,應(yīng)該用正向查詢的語法
res=Book.objects.filter(publish__name='北京出版社').values('title')
print(res) # <QuerySet [{'title': '葵花寶典'}, {'title': '菊花寶典'}, {'title': '桃花寶典'}]>
1.3、多對多查詢(模型類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出版的所有書籍
# 注意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、針對上例中正向查詢的需求:查詢葵花寶典的所有作者孕蝉,如果我們選取的基表是authors屡律,那么就成了反向查詢,應(yīng)該用反向查詢的語法
res=Author.objects.filter(book__title='葵花寶典').values('name')
print(res) # <QuerySet [{'name': 'egon'}, {'name': 'kevin'}]>
# 2降淮、針對上例中反向查詢的需求:查詢作者rose出版的所有書籍疹尾,如果我們選取的基表是Book,那么就成了正向查詢骤肛,應(yīng)該用正向查詢的語法
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個雙下劃線,只需要在每次連雙下劃線時腋颠,確定是正向還是反向即可
# 需求1:查詢北京出版社出版過的所有書籍的名字以及作者的姓名繁成、手機(jī)號
# 方式一:基表為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ī)號以186開頭的作者出版過的所有書籍名稱以及出版社名稱
# 方式一:基表為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)', '大連出版社')
'''