01-Django多表操作實(shí)例

表與表之間的關(guān)系可分為以下三種:
一對(duì)一: 一個(gè)人對(duì)應(yīng)一個(gè)身份證號(hào)碼,數(shù)據(jù)字段設(shè)置 unique。
一對(duì)多: 一個(gè)家庭有多個(gè)人,一般通過(guò)外鍵來(lái)實(shí)現(xiàn)。
多對(duì)多: 一個(gè)學(xué)生有多門(mén)課程,一個(gè)課程有很多學(xué)生,一般通過(guò)第三個(gè)表來(lái)實(shí)現(xiàn)關(guān)聯(lián)


圖片.png
創(chuàng)建模型

接下來(lái)我們來(lái)看下多表多實(shí)例。

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    pub_date = models.DateField()
    publish = models.ForeignKey("Publish", on_delete=models.CASCADE)
    authors = models.ManyToManyField("Author")

class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=64)
    email = models.EmailField()

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)

class AuthorDetail(models.Model):
    gender_choices = (
        (0, "女"),
        (1, "男"),
        (2, "保密"),
    )
    gender = models.SmallIntegerField(choices=gender_choices)
    tel = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    birthday = models.DateField()
說(shuō)明:

1、EmailField 數(shù)據(jù)類型是郵箱格式,底層繼承 CharField,進(jìn)行了封裝,相當(dāng)于 MySQL 中的 varchar。
2、Django1.1 版本不需要聯(lián)級(jí)刪除:on_delete=models.CASCADE,Django2.2 需要。
3、一般不需要設(shè)置聯(lián)級(jí)更新.
4、外鍵在一對(duì)多的多中設(shè)置:models.ForeignKey("關(guān)聯(lián)類名", on_delete=models.CASCADE)。
5、OneToOneField = ForeignKey(...,unique=True)設(shè)置一對(duì)一。
6、若有模型類存在外鍵,創(chuàng)建數(shù)據(jù)時(shí),要先創(chuàng)建外鍵關(guān)聯(lián)的模型類的數(shù)據(jù),不然創(chuàng)建包含外鍵的模型類的數(shù)據(jù)時(shí),外鍵的關(guān)聯(lián)模型類的數(shù)據(jù)會(huì)找不到。

表結(jié)構(gòu)
  • 書(shū)籍表 Book:title 、 price 、 pub_date 、 publish(外鍵,多對(duì)一) 、 authors(多對(duì)多)
  • 出版社表 Publish:name 、 city 、 email
  • 作者表 Author:name 、 age 、 au_detail(一對(duì)一)
  • 作者詳情表 AuthorDetail:gender 、 tel 、 addr 、 birthday
    以下是表格關(guān)聯(lián)說(shuō)明:


    圖片.png
插入數(shù)據(jù)

我們?cè)?MySQL 中執(zhí)行以下 SQL 插入操作:

insert into app01_publish(name,city,email) values 
("華山出版社", "華山", "hs@163.com"), ("明教出版社", "黑木崖", "mj@163.com")
 
""" 先插入 authordetail 表中多數(shù)據(jù)"""
insert into app01_authordetail(gender,tel,addr,birthday) values
(1,13432335433,"華山","1994-5-23"), (1,13943454554,"黑木崖","1961-8-13"),
(0,13878934322,"黑木崖","1996-5-20") 

""" 再將數(shù)據(jù)插入 author,這樣 author 才能找到 authordetail""" 
insert into app01_author(name,age,au_detail_id) values 
("令狐沖",25,1), ("任我行",58,2), ("任盈盈",23,3)

ORM - 添加數(shù)據(jù)
一對(duì)多(外鍵 ForeignKey)
  • 方式一: 傳對(duì)象的形式,返回值的數(shù)據(jù)類型是對(duì)象,書(shū)籍對(duì)象。

步驟:
a. 獲取出版社對(duì)象
b. 給書(shū)籍的出版社屬性 pulish 傳出版社對(duì)象

def add_book(request):
    """  獲取出版社對(duì)象"""
    pub_obj = models.Publish.objects.filter(pk=1).first()
    """  給書(shū)籍的出版社屬性publish傳出版社對(duì)象"""
    book = models.Book.objects.create(
title="菜鳥(niǎo)教程", price=200, pub_date="2010-10-10", publish=pub_obj)
    print(book, type(book))
    return HttpResponse(book)
  • 方式二: 傳對(duì)象 id 的形式(由于傳過(guò)來(lái)的數(shù)據(jù)一般是 id,所以傳對(duì)象 id 是常用的)。
    一對(duì)多中,設(shè)置外鍵屬性的類(多的表)中,MySQL 中顯示的字段名是:外鍵屬性名_id。
    返回值的數(shù)據(jù)類型是對(duì)象,書(shū)籍對(duì)象。

步驟:
a. 獲取出版社對(duì)象的 id
b. 給書(shū)籍的關(guān)聯(lián)出版社字段 pulish_id 傳出版社對(duì)象的 id

def add_book(request):
    """  獲取出版社對(duì)象"""
    pub_obj = models.Publish.objects.filter(pk=1).first()
    """  獲取出版社對(duì)象的id"""
    pk = pub_obj.pk
    """  給書(shū)籍的關(guān)聯(lián)出版社字段 publish_id 傳出版社對(duì)象的id"""
    book = models.Book.objects.create(
           title="沖靈劍法", price=100, pub_date="2004-04-04", publish_id=pk)
    print(book, type(book))
    return HttpResponse(book)
多對(duì)多(ManyToManyField):在第三張關(guān)系表中新增數(shù)據(jù)
  • 方式一: 傳對(duì)象形式,無(wú)返回值。

步驟:
a. 獲取作者對(duì)象
b. 獲取書(shū)籍對(duì)象
c. 給書(shū)籍對(duì)象的 authors 屬性用 add 方法傳作者對(duì)象

def add_book(request):
    """  獲取作者對(duì)象"""
    chong = models.Author.objects.filter(name="令狐沖").first()
    ying = models.Author.objects.filter(name="任盈盈").first()
    """  獲取書(shū)籍對(duì)象"""
    book = models.Book.objects.filter(title="python入門(mén)").first()
    """  給書(shū)籍對(duì)象的 authors 屬性用 add 方法傳作者對(duì)象"""
    book.authors.add(chong, ying)
    return HttpResponse(book)
  • 方式二: 傳對(duì)象id形式,無(wú)返回值。

步驟:
a. 獲取作者對(duì)象的 id
b. 獲取書(shū)籍對(duì)象
c. 給書(shū)籍對(duì)象的 authors 屬性用 add 方法傳作者對(duì)象的 id

def add_book(request):
    """  獲取作者對(duì)象"""
    chong = models.Author.objects.filter(name="令狐沖").first()
    """  獲取作者對(duì)象的id"""
    pk = chong.pk
    """  獲取書(shū)籍對(duì)象"""
    book = models.Book.objects.filter(title="沖靈劍法").first()
    """  給書(shū)籍對(duì)象的 authors 屬性用 add 方法傳作者對(duì)象的id"""
    book.authors.add(pk)

關(guān)聯(lián)管理器(對(duì)象調(diào)用)

前提:

  • 多對(duì)多(雙向均有關(guān)聯(lián)管理器)
  • 一對(duì)多(只有多的那個(gè)類的對(duì)象有關(guān)聯(lián)管理器,即反向才有)

語(yǔ)法格式:

正向:屬性名
反向:小寫(xiě)類名加 _set

注意:一對(duì)多只能反向

常用方法:

1、add():用于多對(duì)多,把指定的模型對(duì)象添加到關(guān)聯(lián)對(duì)象集(關(guān)系表)中。
注意:add() 在一對(duì)多(即外鍵)中,只能傳對(duì)象( QuerySet數(shù)據(jù)類型),不能傳 id([id表])。
*[ ] 的使用:

# 方式一:傳對(duì)象
book_obj = models.Book.objects.get(id=10)
author_list = models.Author.objects.filter(id__gt=2)
book_obj.authors.add(*author_list)  # 將 id 大于2的作者對(duì)象添加到這本書(shū)的作者集合中
# 方式二:傳對(duì)象 id
book_obj.authors.add(*[1,3]) # 將 id=1 和 id=3 的作者對(duì)象添加到這本書(shū)的作者集合中
return HttpResponse("ok")

反向:小寫(xiě)表名_set

ying = models.Author.objects.filter(name="任盈盈").first()
book = models.Book.objects.filter(title="沖靈劍法").first()
ying.book_set.add(book)
return HttpResponse("ok")

2、create():創(chuàng)建一個(gè)新的對(duì)象,并同時(shí)將它添加到關(guān)聯(lián)對(duì)象集之中。
返回新創(chuàng)建的對(duì)象。

pub = models.Publish.objects.filter(name="明教出版社").first()
wo = models.Author.objects.filter(name="任我行").first()
book = wo.book_set.create(title="吸星大法", price=300, pub_date="1999-9-19", publish=pub)
print(book, type(book))
return HttpResponse("ok")

3、remove():從關(guān)聯(lián)對(duì)象集中移除執(zhí)行的模型對(duì)象。
對(duì)于 ForeignKey 對(duì)象,這個(gè)方法僅在 null=True(可以為空)時(shí)存在,無(wú)返回值。

author_obj =models.Author.objects.get(id=1)
book_obj = models.Book.objects.get(id=11)
author_obj.book_set.remove(book_obj)
return HttpResponse("ok")

4、clear():從關(guān)聯(lián)對(duì)象集中移除一切對(duì)象,刪除關(guān)聯(lián),不會(huì)刪除對(duì)象。
對(duì)于 ForeignKey 對(duì)象,這個(gè)方法僅在 null=True(可以為空)時(shí)存在。
無(wú)返回值。

"""  清空獨(dú)孤九劍關(guān)聯(lián)的所有作者"""
book = models.Book.objects.filter(title="獨(dú)孤九劍").first()
book.authors.clear()

ORM 查詢
一、基于對(duì)象的跨表查詢。

正向:屬性名稱
反向:小寫(xiě)類名_set

1、一對(duì)多
查詢主鍵為 1 的書(shū)籍的出版社所在的城市\color{red}{(正向)}。

book = models.Book.objects.filter(pk=1).first()
res = book.publish.city
print(res, type(res))
return HttpResponse("ok")

查詢明教出版社出版的書(shū)籍名\color{red}{(反向)}。
反向:對(duì)象.小寫(xiě)類名_set(pub.book_set) 可以跳轉(zhuǎn)到關(guān)聯(lián)的表(書(shū)籍表)。
pub.book_set.all():取出書(shū)籍表的所有書(shū)籍對(duì)象,在一個(gè) QuerySet 里,遍歷取出一個(gè)個(gè)書(shū)籍對(duì)象。

pub = models.Publish.objects.filter(name="明教出版社").first()
res = pub.book_set.all()
for i in res:
    print(i.title)
return HttpResponse("ok")

2、一對(duì)一
查詢令狐沖的電話\color{red}{(正向)}。
正向:對(duì)象.屬性 (author.au_detail) 可以跳轉(zhuǎn)到關(guān)聯(lián)的表(作者詳情表)

author = models.Author.objects.filter(name="令狐沖").first()
res = author.au_detail.tel
print(res, type(res))
return HttpResponse("ok")

查詢所有住址在黑木崖的作者的姓名\color{red}{(反向)}。
一對(duì)一的反向,用 對(duì)象.小寫(xiě)類名 即可,不用加 _set。
反向:對(duì)象.小寫(xiě)類名(addr.author)可以跳轉(zhuǎn)到關(guān)聯(lián)的表(作者表)。

addr = models.AuthorDetail.objects.filter(addr="黑木崖").first()
res = addr.author.name
print(res, type(res))
return HttpResponse("ok")

3、多對(duì)多
Django教程所有作者的名字以及手機(jī)號(hào)\color{red}{(正向)}。
正向:對(duì)象.屬性(book.authors)可以跳轉(zhuǎn)到關(guān)聯(lián)的表(作者表)。
作者表里沒(méi)有作者電話,因此再次通過(guò)對(duì)象.屬性(i.au_detail)跳轉(zhuǎn)到關(guān)聯(lián)的表(作者詳情表)。

book = models.Book.objects.filter(title="Django教程").first()
res = book.authors.all()
for i in res:
    print(i.name, i.au_detail.tel)
return HttpResponse("ok")

查詢?nèi)挝倚谐鲞^(guò)的所有書(shū)籍的名字\color{red}{(反向)}。

author = models.Author.objects.filter(name="任我行").first()
res = author.book_set.all()
for i in res:
    print(i.title)
return HttpResponse("ok")
二、基于雙下劃線的跨表查詢

正向:屬性名稱__跨表的屬性名稱
反向:小寫(xiě)類名__跨表的屬性名稱

1、一對(duì)多
\color{red}{正向:}查詢江湖出版社出版過(guò)的所有書(shū)籍的名字與價(jià)格。

res = models.Book.objects.filter(
publish__name="江湖出版社").values_list("title", "price")

\color{red}{反向:}通過(guò) 小寫(xiě)類名__跨表的屬性名稱(book__title,book__price) 跨表獲取數(shù)據(jù)。

res = models.Publish.objects.filter(name="江湖出版社").values_list(
"book__title","book__price")
return HttpResponse("ok")

注:
values()得到的是一個(gè)字典形式的查詢集(QuerySet),查詢集是一個(gè)可迭代對(duì)象。
values_list返回的是元組列表,values_list加上flat=True之后返回值列表。

2、多對(duì)多
查詢?nèi)挝倚谐鲞^(guò)的所有書(shū)籍的名字。
\color{red}{正向:}通過(guò) 屬性名稱__跨表的屬性名稱(authors__name) 跨表獲取數(shù)據(jù):

res = models.Book.objects.filter(authors__name="任我行").values_list("title")

\color{red}{反向:}通過(guò) 小寫(xiě)類名__跨表的屬性名稱(book__title) 跨表獲取數(shù)據(jù):

res = models.Author.objects.filter(name="任我行").values_list("book__title")

3、一對(duì)一
查詢?nèi)挝倚械氖謾C(jī)號(hào)。
\color{red}{正向:}通過(guò) 屬性名稱__跨表的屬性名稱(au_detail__tel) 跨表獲取數(shù)據(jù)

res = models.Author.objects.filter(name="任我行").values_list("au_detail__tel")

\color{red}{反向:}通過(guò) 小寫(xiě)類名__跨表的屬性名稱(author__name) 跨表獲取數(shù)據(jù)。

res = models.AuthorDetail.objects.filter(author__name="任我行").values_list("tel")
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容