python之路_django ORM模型(聯表)(二)

1、基於雙下劃線跨表查詢(join查詢)python

  在上一篇中,咱們簡單的介紹了基於對象的跨表查詢,本章將繼續闡述基於雙下劃線的跨表查詢,所用的表格均爲上章中所建立的表格。django

###############基於雙下劃線的查詢:正向查詢,按字段,反向查詢,按表名###############函數

一、一對多spa

實例一(正向,用字段):3d

# 查詢紅樓夢的出版社名稱
#方式1:
ret=Book.objects.filter(title="紅樓夢").values("publish__name")           
print(ret)                                                          # <QuerySet [{'publish__name': '北京出版社'}]>
# 方式2:
res=Publish.objects.filter(book__title="紅樓夢").values("name")          
print(res)                                                          #<QuerySet [{'name': '北京出版社'}]>

實例二(反向,用表名):code

# 查詢沙河出版社出版過的書籍名稱
#方式1:
ret=Publish.objects.filter(name="沙河出版社").values("book__title")
print(ret)                                                         #<QuerySet [{'book__title': '金品梅2'}, {'book__title': '金品梅3'}]>
#方式2:
res=Book.objects.filter(publish__name="沙河出版社").values("title")
print(res)                                                         #<QuerySet [{'title': '金品梅2'}, {'title': '金品梅3'}]>

二、多對多對象

實例一(正向,用字段):blog

# 查詢紅樓夢全部做者的名字
ret=Book.objects.filter(title="紅樓夢").values("authors__name")
print(ret)                                                        #<QuerySet [{'authors__name': 'alex'}, {'authors__name': 'egon'}]>

實例二(反向,用表名):ci

#查詢alex出版過的全部書籍
ret=Author.objects.filter(name="alex").values("book__title")
print(ret)                                                        #<QuerySet [{'book__title': '金品梅2'}, {'book__title': '紅樓夢'}]>

三、一對一get

實例一(正向,用字段):

# 查詢地址在沙河而且email是123的做者的名字
ret=AuthorDetail.objects.filter(adrr="沙河",email=123).values("author__name")
print(ret)                                                        #<QuerySet [{'author__name': 'alex'}]>

實例二(反向,用表名):

# 查詢alex做者的adrr地址
ret = Author.objects.filter(name="alex").values("authordetail__adrr")
print(ret)                                                       #<QuerySet [{'authordetail__adrr': '沙河'}]>

實例三(綜合實例):

#email以456開頭的做者出版過的全部書籍名稱以及出版社名稱  
ret=Book.objects.filter(authors__authordetail__email__startswith="456").values("title","publish__name")
print(ret)

  總結,在上一章的對象查詢中,咱們能夠總結爲全部的查詢是基於一個models對象,而本節中雙下劃線查詢均是基於queryset對象進行的!反向查詢使用的表名一樣必須爲小寫。

2、聚合函數(aggregate)

  aggregate()QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。若是你想要爲聚合值指定一個名稱,能夠向聚合子句提供它。以下例:

#查詢全部書籍的平均價格
# 實例1:
ret=Book.objects.all().aggregate(Avg("price"))
print(ret)                                                         #{'price__avg': 172.66666666666666}
# 實例2:
res = Book.objects.all().aggregate(avgPrice=Avg("price"))
print(res)                                                         #{'avgPrice': 172.66666666666666}

  若是你但願生成不止一個聚合,你能夠向aggregate()子句中添加另外一個參數。因此,若是你也想知道全部圖書價格的最大值和最小值,能夠這樣查詢:

# 查詢全部書籍的平均價格、價格最大值、價格最小值
ret = Book.objects.all().aggregate(Avg("price"),Min("price"),Max("price"))
print(ret)                         #{'price__avg': 172.66666666666666, 'price__min': Decimal('123.00'), 'price__max': Decimal('230.00')}

  以上實例中須要按照以下方式引入相應的模塊方法: from django.db.models import Avg, MaxMin

3、分組函數(annotate)

  annotate()爲調用的QuerySet中每個對象都生成一個獨立的統計值(統計方法用聚合函數)。

  實例1:查詢每個出版社出版過的書籍個數

ret=Publish.objects.all().annotate(num=Count("book__title"))     #能夠理解爲每個出版社對象增長一個num字段,該字段值是經過聚合函數聯表求得
for pub_obj  in ret:
    print(pub_obj.name,pub_obj.num)

  annotate的返回值是querySet,若是不想遍歷對象,能夠用上values_list,以下:

ret = Publish.objects.all().annotate(num=Count("book__title")).values_list("name","num")
print(ret)                                                       #<QuerySet [('人民出版社', 0), ('沙河出版社', 2), ('北京出版社', 1)]>

  實例2:查詢每一本書的做者個數

ret=Book.objects.all().annotate(counts=Count("authors__nid")).values("title","counts")
print(ret)        #<QuerySet [{'title': '金品梅2', 'counts': 2}, {'title': '金品梅3', 'counts': 2}, {'title': '紅樓夢', 'counts': 2}]>

 4、練習題解析

  以下例爲1-5分別使用基於對象查詢和雙下劃線查詢:

# 一、查詢人民出版社出版過的價格大於100的書籍的做者的email
# 方法一:
pub_obj = Publish.objects.get(name="人民出版社")
book_obj = pub_obj.book_set.filter(price__gt=100)
for book in book_obj:
print(book.authors.all())
for author in book.authors.all():
    print(author.authordetail.email)
#方法二:
pub_obj=Publish.objects.get(name="人民出版社")
ret=pub_obj.book_set.filter(price__gt=100).values("authors__authordetail__email")
print(ret)
# 二、查詢alex出版過的全部書籍的名稱以及書籍的出版社的名稱
#方法1:
book_obj=Author.objects.get(name="alex").book_set.all()
for book in book_obj:
print(book.title,book.publish.name)
# 方法2:
ret=Book.objects.filter(authors__name="alex").values("title","publish__name")
print(ret)
# 三、查詢2011年出版社過的全部書籍的做者名字以及出版社名稱
#方法一:
book_obj= Book.objects.filter(publishDate__year=2011)
for book in book_obj:
print(book.authors.all().values("name"),book.publish.name)
#方法二:
ret=Book.objects.filter(publishDate__year=2011).values("authors__name","publish__name")
print(ret)
# 四、查詢住在沙河而且email以123開頭的做者寫過的全部書籍名稱以及書籍的出版社名稱
#方法一:
book_obj=AuthorDetail.objects.get(adrr="沙河", email__startswith=123).author.book_set.all()
for book in book_obj:
print(book.title,book.publish.name)

#方法二:
ret=AuthorDetail.objects.filter(adrr="沙河",email__startswith=123).values("author__book__title","author__book__publish__name")
print(ret)
# 五、查詢年齡大於20歲的做者在哪些出版社出版過書籍
#方法一:
author_obj = Author.objects.filter(age__gt=20)
for author in author_obj:
# print(author.book_set.all())
for book in author.book_set.all():
    print(book.publish.name)
#方法二:
ret=Author.objects.filter(age__gt=20).values("book__authors__name","book__publish__name")
print(ret)

# 六、查詢每個出版社的名稱以及出版過的書籍個數
ret=Publish.objects.all().annotate(counts=Count("book__nid")).values("name","counts")
print(ret)
# 七、查詢每個做者的名字以及出版過的全部書籍的最高價格
ret=Author.objects.all().annotate(max_price=Max("book__price")).values("name","max_price")
print(ret)
# 八、查詢每一本書的名字,對應出版社名稱以及做者的個數
ret=Book.objects.all().annotate(counts=Count("authors__nid")).values("title","publish__name","counts")
print(ret)

5、F查詢與Q查詢

  具體介紹以下:

一、F查詢

二、Q查詢

相關文章
相關標籤/搜索