Django模型 - 多表操做

一 建立模型

做者模型:一個做者有姓名和年齡。python

做者詳細模型:把做者的詳情放到詳情表,包含生日,手機號,家庭住址等信息。做者詳情模型和做者模型之間是一對一的關係(one-to-one)django

出版社模型:出版社有名稱,所在城市以及email。函數

書籍模型: 書籍有書名和出版日期,一本書可能會有多個做者,一個做者也能夠寫多本書,因此做者和書籍的關係就是多對多的關聯關係(many-to-many);一本書只應該由一個出版商出版,因此出版商和書籍是一對多關聯關係(one-to-many)。spa

生成表以下:code


1

二 多表添加

一對一新增 (能夠傳對象或id)

先建立沒有外鍵的數據,而後類的字段等於對象(方式一)對象

authordetail = AuthorDetail.objects.create(phone='19856482547',email='4878779@qq.com')
author = Author.objects.create(name='張三',age=28,authordetail=authordetail)

直接知道姓名給authordetail_id 賦值  (方式二)blog

author = Author.objects.create(name='安妮',age=12,authordetail_id=7)
 print(author)

一對多增長

方式一 (同上)排序

publish = Publish.objects.create(name='北京出版社',addr='北京西路',email='887@163.com')
book = Book.objects.create(name='花非花',price=34,pub_date='1972-9-4',publish=publish)

方式二rem

publish = Publish.objects.filter(name='北京出版社').first()
 book = Book.objects.create(name='霧非霧',price=36,pub_date='1972-9-4',publish_id=publish.nid)

多對多增長

book = Book.objects.create(name='西遊記',price=78,pub_date='2017-9-2',publish_id=3)
      
    # 多對多,添加關係add ,傳對應的(做者nid)id  book.author.add(1,2)
    # 沒有返回值
    # ret = book.author.add(3,6)
    # ret = book.author.add(*(3,6))
    #add裏面能夠傳對象,也能夠傳多個,以逗號分隔,也能夠*(做者對象,做者對象)
 book = Book.objects.create(name='FOX',price=34,pub_date='2017-7-19',publish_id=3)
 author = Author.objects.filter(pk=7).first()
 book.author.add(author)


多對多關係解除綁定

remove  get

解除綁定關係(既能夠傳對象 又能夠傳author_id,既能夠傳多個又能夠傳一個)  移除一條或多條
book = Book.objects.filter(pk=8).first()
  # ret = book.author.remove(author.id)
 ret = book.author.remove(7)

 author = Author.objects.filter(pk=6).first()
 ret = book.author.remove(author)
    # ret = book.author.remove(2,5)
    # ret = book.author.remove(*(2,5))

clear 一次性解除所有綁定關係

book = Book.objects.filter(pk=8).first()
book.author.clear()

set  參數必須傳入可迭代對象,能夠傳id,也能夠傳對象

book = Book.objects.filter(pk=6).first()
 author = Author.objects.filter(pk=3).first()
 book.author.set([author])

#先執行clear,再執行add  先清空在添加

三 基於對象正反向查詢

一對一

查詢安妮的電話號碼(正向查詢 按字段)
    # anni = Author.objects.filter(name='安妮').first()

    # print(anni.authordetail.phone,type(anni.authordetail))

查詢電話號碼是 13956485512 的做者(反向查 按表名小寫)
    # authordetail = AuthorDetail.objects.filter(phone='13956485512').first()
    # print(authordetail.author)
    # print(authordetail.author.name)

一對多

#查詢紅樓夢是哪一個出版社
    # 正向查
    # 反向查
    '''
    A表book(關聯字段)    B表 publish
    正向查詢  A--->B      關聯字段在A,A去查詢B表,這叫正向查詢,按字段來查
    反向查詢  B--->A      關聯字段在A,B去查詢A表,這叫正向查詢,按表名小寫_set
    
    '''
# 正向查詢
# book = Book.objects.filter(name='紅樓夢').first()
# print(book.publish.name)
# 反向查詢
# 北京出版社全部書
# publish = Publish.objects.filter(name='北京出版社').first()

# print(publish.book_set.all())

多對多

#查詢紅樓夢這本書全部做者(正向 按字段)
# book = Book.objects.filter(name='紅樓夢').first()
# print(book.author.all())

#查詢張三出的全部書( 反向查 按表名小寫_set)
# zs = Author.objects.filter(name='張三').first()
# print(zs.book_set.all())

'''
 A表book(關聯字段)   B表 publish
 正向查  A -->B
 反向查  B -->A  
 
總結:
  正向查詢按字段 反向查詢按表名小寫告訴ORM引擎join那張表
    一對一  正向: 按字段  反向: 按表名小寫
    一對多  正向: 按字段  反向: 按表名小寫_set
    多對多  正向: 按字段  反向: 按表名小寫_set
 

'''


四 基於雙下滑線的多表查詢(連表查詢)

一對多查詢

查詢北京出版社出版過的全部書籍價格、名字(反向 )
# ret = Publish.objects.filter(name='北京出版社').values('book__price','book__name')
# print(ret)
正向
# res = Book.objects.filter(publish__name='北京出版社').values('name','price')
# print(res)

多對多查詢

#查詢王五出過的全部書籍名字、價格(多對多)
#正向
# ret = Book.objects.filter(author__name='王五').values('name','author__name','author__authordetail__phone')
# ret = Book.objects.filter(author__name='王五').values('name','price')
# print(ret)
#反向
# ret = Author.objects.filter(name='王五').values('book__name','book__price')
# print(ret)

一對一

查詢王五的手機號(正向)
# ret = Author.objects.filter(name='王五').values('authordetail__phone')
# print(ret)
#反向 按表名小寫
# ret = AuthorDetail.objects.filter(author__name='王五').values('phone')
# print(ret)
'''
總結: 
    用__告訴ORM ,要鏈接哪一個表
        一對一  正向: 按字段  反向:按表名小寫
        一對多  正向: 按字段  反向:按表名小寫
        多對多  正向: 按字段  反向:按表名小寫
'''

# 手機號以13開頭的做者出過的全部書籍名稱以出版社名稱
# ret = Book.objects.filter(author__authordetail__phone__startswith='13').values('name','publish__name')
# print(ret)
# ret = AuthorDetail.objects.filter(phone__startswith='13').values('author__book__name','author__book__publish__name')
# print(ret)
# ret = Author.objects.filter(authordetail__phone__startswith='13').values('book__name','book__publish__name')
# print(ret)
# ret = Publish.objects.filter(book__author__authordetail__phone__startswith='13').values('name','book__name')
# print(ret)

五 聚合查詢和分組查詢

聚合

聚合 aggregete
# 計算全部圖書的平均價格
from django.db.models import Avg,Max,Min,Count,Sum
# ret = Book.objects.all().aggregate(c=Avg('price'))
# print(ret)

# 計算全部圖書總價
# ret = Book.objects.all().aggregate(s=Sum('price'))
# print(ret)

# 最大價格
# ret = Book.objects.all().aggregate(m=Max('price'))
# print(ret)

# 全部圖書價格最大值個最小值,返回結果是字典
# ret = Book.objects.all().aggregate(b_max=Max('price'),b_min=Min('price'))
# print(ret)

分組

annotate()爲調用queryset中每個對象都生成獨立的統計值
#跨表分組查詢本質就是將關聯表join成一張表,再按單表的思路進行分組

from django.db.models import Avg,Max,Sum,Min,Count
# 統計每本書的做者數
# book_list = Book.objects.all().annotate(author_num=Count('author','author'))
# for book in book_list:
#     print(book.name,':',book.author_num)
#同上   values 在這裏指group_by 的字段
ret = Book.objects.values('name').annotate(author_num=Count('author__name')).values('name','author_num')
print(ret)
# book_list = Book.objects.all().annotate(author_num=Count('author')).values('name','author_num')
# print(book_list)

# 統計每一出版社的最便宜的書
# ret = Publish.objects.all().annotate(p=Min('book__price')).values('name','p')
# print(ret)

# 統計每一本以 紅 開頭的書籍的做者個數
# ret = Book.objects.all().filter(name__startswith='紅').annotate(num=Count('author')).values('name','num')
# print(ret)

# ret = Book.objects.filter(name__startswith='西').annotate(num=Count('author')).values('name','num')
# print(ret)

# 統計不止一個做者的圖書:(做者數量大於1)
# ****注意values在annotate前,表明group by的字段,不寫values 默認以基表的主鍵作group by 在後代我要select出來字段
# ret = Book.objects.all().values('name').annotate(num=Count('author__name')).filter(num__gt=1).values('name','num')
# print(ret)

# ret = Book.objects.all().annotate(num=Count('author')).filter(num__gt=1).values('name','num')
# print(ret)

# 根據一本圖書做者數量的多少對查詢集queryset進行排序
# ret = Book.objects.annotate(num=Count('author')).order_by('num').values('name','num')
# print(ret)

# 查詢各個做者出的書的總價格
# ret = Author.objects.all().annotate(p=Sum('book__price')).values('name','p')
# print(ret)

#查詢每一個出版社的名稱和書籍個數
# ret = Publish.objects.annotate(num=Count('book')).values('name','num')
# print(ret)

六 F查詢和 Q查詢

F查詢

F() 的實例能夠在查詢中引用字段,來比較同一個 model 實例中兩個不一樣字段的值。

# 查詢評論數大於收藏數的書籍
 from django.db.models import F
 Book.objects.filter(commnetNum__lt=F('keepNum'))

Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操做。

# 查詢評論數大於收藏數2倍的書籍
Book.objects.filter(commnetNum__lt=F('keepNum')*2)

修改操做也可使用F函數,好比將每一本書的價格提升30元:

Book.objects.all().update(price=F("price")+30)

Q查詢

filter() 等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。 若是你須要執行更復雜的查詢(例如OR 語句),你可使用Q 對象

名字叫花非花 或者price是39的數   | 或     & 和     ~# ret = Book.objects.all().filter(Q(name='花非花')|Q(price='39'))

你能夠組合&|  操做符以及使用括號進行分組來編寫任意複雜的Q 對象。同時,Q 對象可使用~ 操做符取反,這容許組合正常的查詢和取反(NOT) 查詢:

查詢函數能夠混合使用Q 對象和關鍵字參數。全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")
相關文章
相關標籤/搜索