1、查詢(重點)sql
正向查詢和反向查詢django
關係屬性(字段)寫在哪一個表裏面,從當前類(表)的數據去查詢它關聯類(表)的數據叫作正向查詢,反之叫作反向查詢app
正向查詢
# 1.查詢jiege的地址
author_obj = models.Author.objects.get(name='jiege')
print(author_obj.authorDetail.addr)函數
# 或者用filter這種查,可是要加.first()變成models對象,不然報錯 author_obj1 = models.Author.objects.filter(name='jiege').first() print(author_obj1.authorDetail.addr) # 正向 author_obj.authorDetail 也就是 對象.關聯屬性名稱
反向查詢
# 2.查詢 1996-02-14 是誰的生日
authordetail_obj = models.AuthorDetail.objects.get(birthday='1996-02-14')
print(authordetail_obj.author.name)工具
# 反向 authordetail_obj.author 也就是 對象.小寫的另外一個表名(類名)
總結
Author表 一對一關聯 AuthorDetail表fetch
正向查詢:Authorobj.authorDetail,對象.關聯屬性名稱 Author------------------------------------------------->AuthorDetail <------------------------------------------------- 反向查詢:AuthorDetailobj.author ,對象.小寫類名
正向查詢
# 1.查詢 回村的誘惑 這本書是哪一個出版社出版的
book_obj = models.Book.objects.get(title='回村的誘惑')
print(book_obj.publish.name)code
# 正向 book_obj.publish 也就是 對象名.關聯屬性名稱
反向查詢
# 2.查詢 外交出版社 都出版了哪些書
publish_obj = models.Publish.objects.get(name='外交出版社')
print(publish_obj.book_set.all()) # <QuerySet [<Book: yuhao的回憶錄>, <Book: 傑哥你真猛>]>
print(publish_obj.book_set.all().filter(price__gt=500)) # <QuerySet [<Book: 傑哥你真猛>]>orm
# 反向 publish_obj.book_set 也就是 對象.表名小寫_set # 由於一個出版社能夠對應不少書,因此用 book_set # 由於結果返回一個queryset對象,能夠繼續加 .方法
總結
Book表 一對多關聯 Publish表對象
正向查詢:book_obj.publish,對象.關聯屬性名稱 Book -------------------------------------------------> Publish <------------------------------------------------- 反向查詢:publish_obj.book_set.all(),對象.表名小寫_set
正向查詢
# 1.查詢 yuhao的回憶錄 這本書的做者都有誰
book_obj = models.Book.objects.get(title='yuhao的回憶錄')
print(book_obj.authors.all()) # <QuerySet [<Author: jiege>, <Author: yuhao>, <Author: liangdao>]>事務
# 正向 book_obj.authors.all() 就是 對象.屬性
反向查詢
# 2.查詢 liangdao 都寫過哪些書
author_obj = models.Author.objects.get(name='liangdao')
print(author_obj.book_set.all()) # <QuerySet [<Book: yuhao的回憶錄>, <Book: 裝13是如何煉成的2>]>
# 反向 book_obj.author_obj.book_set.all() 就是 對象.表名小寫_set
總結
Book表 多對多關聯 Author表
正向查詢:book_obj.authors.all(),對象.關聯屬性名稱 Book -------------------------------------------------> Author <------------------------------------------------- 反向查詢:author_obj.book_set.all(),對象.表名小寫_set
正向查詢和反向查詢
查詢 jiege 的地址
# 方式1:正向查詢
obj = models.Author.objects.filter(name='jiege').values('authorDetail__addr')
print(obj) # <QuerySet [{'authorDetail__addr': '天空之城'}]>
# 方式2:反向查詢 obj1 = models.AuthorDetail.objects.filter(author__name='jiege').values('addr') print(obj1) # <QuerySet [{'addr': '天空之城'}]>
哪一個做者的生日是 2019 - 07 - 19
# 方式1:正向查詢
obj = models.Author.objects.filter(authorDetail__birthday='2019-07-19').values('name')
print(obj) # <QuerySet [{'name': 'liangge'}]>
# 方式2:反向查詢 obj1 = models.AuthorDetail.objects.filter(birthday='2019-07-19').values('author__name') print(obj1) # <QuerySet [{'author__name': 'liangge'}]>
查詢一下 裝13是如何煉成的 這本書的出版社是哪一個
# 方式1:正向查詢
obj = models.Book.objects.filter(title='裝13是如何煉成的').values('publish__name')
print(obj) # <QuerySet [{'publish__name': '膨脹出版社'}]>
# 方式2:反向查詢 obj1 = models.Publish.objects.filter(book__title='裝13是如何煉成的').values('name') print(obj1) # <QuerySet [{'name': '膨脹出版社'}]>
膨脹出版社 出版了哪些書
# 方式1:正向查詢
obj = models.Book.objects.filter(publish__name='膨脹出版社').values('title')
print(obj)
# <QuerySet [{'title': '裝13是如何煉成的'}, {'title': '回村的誘惑'}, {'title': '裝13是如何煉成的2'}, {'title': '傑哥誘惑'}]>
# 方式2:反向查詢 obj1 = models.Publish.objects.filter(name='膨脹出版社').values('book__title') print(obj1) # <QuerySet [{'book__title': '裝13是如何煉成的'}, {'book__title': '回村的誘惑'}, {'book__title': '裝13是如何煉成的2'}, {'book__title': '傑哥誘惑'}]>
傑哥誘惑 這本書是誰寫的
# 方式1:正向查詢
obj = models.Book.objects.filter(title='傑哥誘惑').values('authors__name')
print(obj) # <QuerySet [{'authors__name': 'yuhao'}]>
# 方式2:反向查詢 obj1 = models.Author.objects.filter(book__title='傑哥誘惑').values('name') print(obj1) # <QuerySet [{'name': 'yuhao'}]>
yuhao 都寫了哪些書
# 方式1:正向查詢
obj = models.Book.objects.filter(authors__name='yuhao').values('title')
print(obj)
# <QuerySet [{'title': '裝13是如何煉成的'}, {'title': 'yuhao的回憶錄'}, {'title': '裝13是如何煉成的2'}, {'title': '傑哥誘惑'}]>
# 方式2:反向查詢 obj1 = models.Author.objects.filter(name='yuhao').values('book__title') print(obj1) # <QuerySet [{'book__title': '裝13是如何煉成的'}, {'book__title': 'yuhao的回憶錄'}, {'book__title': '裝13是如何煉成的2'}, {'book__title': '傑哥誘惑'}]>
裝13出版社 出版的書的名稱以及做者的名字
# 關聯了三張表,Book、Author、publish
方式一: obj = models.Publish.objects.filter(name='裝13出版社').values('book__title','book__authors__name') print(obj) # <QuerySet [{'book__title': '回孃家的誘惑', 'book__authors__name': 'jiege'}, {'book__title': '回孃家的誘惑', 'book__authors__name': 'yuhao'}]> 方式二: obj1 = models.Book.objects.filter(publish__name='裝13出版社').values('title','authors__name') print(obj1) # <QuerySet [{'title': '回孃家的誘惑', 'authors__name': 'jiege'}, {'title': '回孃家的誘惑', 'authors__name': 'yuhao'}]> 方式三: obj2 = models.Author.objects.filter(book__publish__name='裝13出版社').values('book__title','name') print(obj2) # <QuerySet [{'book__title': '回孃家的誘惑', 'name': 'jiege'}, {'book__title': '回孃家的誘惑', 'name': 'yuhao'}]>
原生的sql語句是這樣的:
SELECT
app01_book.title,
app01_author.name
FROM
app01_publish
INNER JOIN app01_book ON app01_publish.nid = app01_book.publish_id
INNER JOIN app01_book_authors ON app01_book.nid = app01_book_authors.book_id
INNER JOIN app01_author ON app01_author.nid = app01_book_authors.author_id
WHERE
app01_publish.name = '裝13出版社';
使用Navicat工具:
手機號以4開頭的做者出版過的全部書籍名稱以及出版社名稱
# 關聯了四張表,Book、Author、publish、AuthorDetail
# 方式一 obj = models.AuthorDetail.objects.filter(telephone__startswith='4').values('author__book__title','author__book__publish__name') print(obj) # 方式二 obj1 = models.Book.objects.filter(authors__authorDetail__telephone__startswith='4').values('title','publish__name') print(obj1) # 方式三 obj2 = models.Publish.objects.filter(book__authors__authorDetail__telephone__startswith='4').values('book__title','name') print(obj2) # 方式四 obj3 = models.Author.objects.filter(authorDetail__telephone__startswith='4').values('book__title','book__publish__name') print(obj3)
3.related_name
反向查詢時,若是定義了related_name ,則用related_name替換 表名,
注意:,用在外鍵的建立 ForeignKey 中的一個參數,只會影響反向查詢
例如:
# 在建立Book表的時候 class Book(models.Model): ...... publish=models.ForeignKey(to="Publish", to_field = "nid", on_delete = models.CASCADE,related_name='xx') ...... # 由於定義了related_name='xx',因此 # 在正向查詢時,不會影響什麼 # 在反向查詢時,就不會用小寫的表名了,而是必須用'xx',不然會報錯 好比查詢 裝13是如何煉成的 這本書的出版社的名字 正向查詢: obj = models.Book.objects.filter(title='裝13是如何煉成的').values('publish__name') print(obj) 反向查詢: # 沒加related_name='xx' obj1 = models.Publish.objects.filter(book__title='裝13是如何煉成的').values('name') print(obj1) # 加入了related_name='xx' obj1 = models.Publish.objects.filter(xx__title='裝13是如何煉成的').values('name') print(obj1)
2、聚合查詢
計算全部圖書的平均價格、最高價格
from django.db.models import Avg,Max,Min,Count obj = models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price')) print(obj) # {'a': 411.998571, 'm': Decimal('998.00')}
注意點:
annotate()爲調用的QuerySet中每個對象都生成一個獨立的統計值(統計方法用聚合函數)。
ret = models.Publish.objects.annotate(a=Avg('book__price')).values('a') print(ret) # <QuerySet [{'a': 449.2475}, {'a': 188.0}, {'a': 449.5}]> ret1 = models.Book.objects.values('publish_id').annotate(a=Avg('price')) print(ret1) # <QuerySet [{'publish_id': 1, 'a': 449.2475}, {'publish_id': 2, 'a': 188.0}, {'publish_id': 3, 'a': 449.5}]> ret2 = models.Emp.objects.values('dep_id','name').annotate(a=Count(1)) # 這裏若是你寫了其餘字段,那麼只有這兩個字段重複,纔算一組,合併到一塊兒來統計個數
注意點:
6、F查詢、Q查詢
針對本身單表中字段的比較和處理,有三種功能
好比在Book表中新建兩個字段,一個收藏數(keep_num),一個評論數(comment_num)
須要先引入:from django.db.models import F
本身單表中字段的比較
# 查詢Book本身這張單表中 收藏數 大於 評論數 的書
ret = models.Book.objects.filter(keep_num__gt=F('comment_num'))
print(ret)
# <QuerySet [<Book: 裝13是如何煉成的>, <Book: yuhao的回憶錄>, <Book: 裝13是如何煉成的2>]>
F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操做
# 查詢Book表中 收藏數 大於 評論數的2倍 的書
ret = models.Book.objects.filter(keep_num__gt=F('comment_num')*2)
print(ret)
# <QuerySet [<Book: 裝13是如何煉成的>, <Book: 裝13是如何煉成的2>]>
修改、批量的修改操做也可使用F函數
# 給全部書的價格都減小20
ret = models.Book.objects.all().update(price=F('price')-20)
print(ret)
.
Q查詢
由於查詢的時候,.filter()等方法中的關鍵字查詢都是 and 的關係,表示不了 or 的關係 ,此時, Q查詢就會派上用場
Q 對象可使用&(與) 、|(或)、~(非) 操做符組合起來。
當一個操做符在兩個 Q對象 上使用時,它產生一個新的 Q對象。
先引入:from django.db.models import Q
使用&、|、~
ret = models.Book.objects.filter(Q(title='裝13是如何煉成的')|Q(price__lt=100))
print(ret)
# 等同於: where title='裝13是如何煉成的' or price<100;
優先級問題(非>與>或),嵌套可解決
# 此時由於and的優先級高於or,因此先找價格小於100而且評論數大於100的 或者出版日期的年份是2019的書
ret = models.Book.objects.filter(Q(publishDate__year=2019)|Q(price__lt=100)&Q(comment_num__gt=100))
print(ret)
# 由於加入了Q()嵌套,因此是查詢出版日期的年份是2019或者價格小於100的 而且 評論數大於100的書 ret = models.Book.objects.filter(Q(Q(publishDate__year=2019)|Q(price__lt=100))&Q(comment_num__gt=100))
混合使用 Q 對象和關鍵字參數
全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面。
ret = models.Book.objects.filter(Q(publishDate__year=2019)&Q(price__lt=100),title__icontains='yuhao')
print(ret)
綜合練習
查詢每一個做者的姓名以及出版的書的最高價格
ret = models.Author.objects.annotate(m=Max('book__price')).values('name','m')
print(ret)
查詢做者id大於2做者的姓名以及出版的書的平均價格
ret = models.Author.objects.filter(nid__gt=2).annotate(a=Avg('book__price')).values('name','a')
print(ret)
查詢做者id大於2或者做者年齡大於等於20歲的女做者的姓名以及出版的書的最高價格
ret = models.Author.objects.filter(Q(nid__gt=2)|Q(age__gte=20),sex='female').annotate(m=Max('book__price')).values('name','m')
print(ret)
查詢每一個做者出版的書的最高價格 的平均值
ret = models.Author.objects.annotate(m=Max('book__price')).values('m').aggregate(b=Avg('m'))
print(ret)
每一個做者出版的全部書的價格以及最高價格的那本書的名稱
ret = models.Author.objects.annotate(m=Max('book__price')).values('book__price','book__title')
print(ret)
# orm沒法解決這個問題,此時查出來的數據不正確(由於書的名字分組只取到了第一個,而不是最大的那個名字)
在原生sql中: # sql_mode = only_full_group_by 設置這個模式 select * from (SELECT app01_author.id,app01_author.name,max(app01_book.price) as m FROM app01_author INNER JOIN app01_book_authors on app01_author.id=app01_book_authors.author_id INNER JOIN app01_book on app01_book_authors.book_id = app01_book.nid GROUP BY app01_author.id,app01_author.name) as t1 INNER JOIN app01_book_authors on t1.id=app01_book_authors.author_id INNER JOIN app01_book on app01_book.nid=app01_book_authors.book_id where t1.m=app01_book.price; # sql_mode != onlu_full_group_by SELECT app01_author.id,app01_book.title,app01_book.price FROM app01_author INNER JOIN app01_book_authors on app01_author.id=app01_book_authors.author_id INNER JOIN app01_book on app01_book_authors.book_id = app01_book.nid ORDER BY app01_book.price desc
orm執行原生sql語句(瞭解)
Django 提供兩種方法使用原始SQL進行查詢:一種是使用raw()方法,進行原始SQL查詢並返回模型實例;另外一種是徹底避開模型層,直接執行自定義的SQL語句。
執行原生查詢
注:raw()語法查詢必須包含主鍵
# 方式一:
models.Publish.objects.raw('原生sql')
models.Publish.objects.raw('select * from app01_pubblish')
# 方式二: from django.db import connection cursor = connection.cursor() cursor.excute('原生sql',[1,]) cursor.fetchall()
展現sql的
models.Book.objects.filter(good__gt=F('comment')*2)
from django.db import connection
print(connection.queries)
事務四大特性:一致性、持久性、隔離性、原子性
提交事務:start--執行修改---submit提交,rollback回滾取消