05-02 Django之模型層第二篇:多表操作

目錄

  • 一 表關(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)', '大連出版社')
'''

加qq群830644110獲取更多高級文章&項目源代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市淑玫,隨后出現(xiàn)的幾起案子巾腕,更是在濱河造成了極大的恐慌,老刑警劉巖絮蒿,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尊搬,死亡現(xiàn)場離奇詭異,居然都是意外死亡土涝,警方通過查閱死者的電腦和手機(jī)佛寿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來但壮,“玉大人冀泻,你說我怎么就攤上這事±” “怎么了弹渔?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長溯祸。 經(jīng)常有香客問我肢专,道長舞肆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任博杖,我火速辦了婚禮椿胯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘欧募。我一直安慰自己,他們只是感情好仆抵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布跟继。 她就那樣靜靜地躺著,像睡著了一般镣丑。 火紅的嫁衣襯著肌膚如雪舔糖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天莺匠,我揣著相機(jī)與錄音金吗,去河邊找鬼。 笑死趣竣,一個胖子當(dāng)著我的面吹牛摇庙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播遥缕,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼卫袒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了单匣?” 一聲冷哼從身側(cè)響起夕凝,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎户秤,沒想到半個月后码秉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸡号,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年转砖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲸伴。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡堪藐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挑围,到底是詐尸還是另有隱情礁竞,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布杉辙,位于F島的核電站模捂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜狂男,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一综看、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岖食,春花似錦红碑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔑穴,卻和暖如春忠寻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背存和。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工奕剃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捐腿。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓纵朋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親茄袖。 傳聞我的和親對象是個殘疾皇子倡蝙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容