一、多表查詢
1、基於雙下劃線的跨表查詢
Django 還提供了一種直觀而高效的方式在查詢(lookups)中表示關聯關係,它能自動確認 SQL JOIN 聯絡。要做跨關係查詢,就使用兩個下劃線來連結模型(model)間關聯欄位的名稱,直到最終連結到你想要的model 為止。
語法:正向查詢按欄位,反向查詢按表名小寫,用來告訴ORM引擎join哪張表。
a、一對多查詢
示例一:查詢蘋果出版社出版過的所有書籍的名字與價格
# 正向查詢 按欄位:publish
queryResult=Book.objects.filter(publish__name="蘋果出版社").values_list("title","price")
# 反向查詢 按表名小寫:book
queryResult=Publish.objects.filter(name="蘋果出版社").values_list("book__title","book__price"
示例二:查python這本書的出版社的名字和郵箱
# 正向查詢
Book.objects.filter(title="python").values("publish__name", "publish__email")
# 反向查詢
Publish.objects.filter(book__title="python").values("name", "email")
b、多對多查詢
示例一:查詢alex出過的所有書籍的名字
# 正向查詢 按欄位:authors:
queryResult=Book.objects.filter(authors__name="yuan").values_list("title")
# 反向查詢 按表名小寫:book
queryResult=Author.objects.filter(name="yuan").values_list("book__title","book__price")
示例二:查詢python這本書的作者的年齡
# 正向查詢
Book.objects.filter(title="python").values("author__age")
# 反向查詢
Author.objects.filter(book__title="python").values("age")
c、一對一查詢
示例一:查詢alex的手機號
# 正向查詢 按欄位:authorDetail
ret=Author.objects.filter(name="alex").values("authorDetail__telephone")
# 反向查詢 按表名小寫:author
ret=AuthorDetail.objects.filter(author__name="alex").values("telephone")
示例二:查詢手機號為133的作者的名字
# 正向查詢
Author.objects.filter(authorDetail__telephone__startswith="133").values("name")
# 反向查詢
AuthorDetail.objects.filter(telephone__startswith="133").values("author__name")
d、進階練習(連續跨表)
示例一:查詢人民出版社出版過的所有書籍的名字以及作者的姓名
# 正向查詢
queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","authors__name")
# 反向查詢
queryResult=Publish.objects.filter(name="人民出版社") .values_list("book__title","book__authors__age","book__authors__name")
示例二:手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱
# 方式1:
queryResult=Book.objects.filter(authors__authorDetail__telephone__startswith="151") .values_list("title","publish__name")
# 方式2:
ret=Author.objects.filter(authorDetail__telephone__startswith="151") .values("book__title","book__publish__name")
e、related_name相關
反向查詢時,如果定義了related_name ,則用related_name的值替換表名,例如:
publish = ForeignKey(Blog, related_name='bookList')
示例一:查詢人民出版社出版過的所有書籍的名字與價格(一對多)
# 反向查詢 不再按表名:book,而是related_name的值bookList
queryResult=Publish.objects.filter(name="人民出版社").values_list("bookList__title","bookList__price")
2、聚合查詢
語法:aggregate(*args, **kwargs)
示例一:計算所有圖書的平均價格
from django.db.models import Avg # 首先匯入聚合函式Avg ret = Book.objects.all().aggregate(Avg('price')) print(ret) # 結果為:{'price__avg': 34.35}
aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。鍵的名稱是聚合值的識別符號,值是計算出來的聚合值。鍵的名稱是按照欄位和聚合函式的名稱自動生成出來的。如果你想要為聚合值指定一個名稱,可以向聚合子句提供它。並且all()方法也可以不寫,預設查詢所有,如下示例:
ret = Book.objects.aggregate(average_price=Avg('price')) print(ret) # 結果為:{'average_price': 34.35}
如果你希望生成不止一個聚合函式,你可以向aggregate()子句中新增另一個引數。所以,如果你也想知道所有圖書價格的最大值和最小值,可以這樣查詢:
from django.db.models import Avg, Max, Min # 匯入聚合函式 ret = Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) print(ret) # 結果為:{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
3、分組查詢
a、單表分組查詢
示例一:查詢每一個部門名稱以及對應的員工數,員工表如下:
emp表: id name age salary dep 1 alex 12 2000 銷售部 2 egon 22 3000 人事部 3 wen 22 5000 人事部
SQL語句:select dep,Count(*) from emp group by dep;
ORM:emp.objects.values("dep").annotate(c=Count("id")
b、多表分組查詢
示例一:查詢每一個部門名稱以及對應的員工數,表如下:
emp表: id name age salary dep_id 1 alex 12 2000 1 2 egon 22 3000 2 3 wen 22 5000 2 dep表: id name 1 銷售部 2 人事部 emp-dep: id name age salary dep_id id name 1 alex 12 2000 1 1 銷售部 2 egon 22 3000 2 2 人事部 3 wen 22 5000 2 2 人事部
SQL語句:select dep.name,Count(*) from emp left join dep on emp.dep_id=dep.id group by dep.id;
ORM:dep.objetcs.values("id").annotate(c=Count("emp")).values("name","c")
總結:
1)annotate()為呼叫的QuerySet中每一個物件都生成一個獨立的統計值(統計方法用聚合函式)。
2)跨表分組查詢本質就是將關聯表join成一張表,再按單表的思路進行分組查詢。
c、查詢練習
示例一:統計每一個出版社的最便宜的書
publishList = Publish.objects.annotate(MinPrice=Min("book__price")) for publish_obj in publishList: print(publish_obj.name,publish_obj.MinPrice)
annotate的返回值是querySet,如果不想遍歷物件,可以用上value_list()方法,如下:
queryResult = Publish.objects.annotate(MinPrice=Min("book__price")).values_list("name","MinPrice") print(queryResult)
示例二:統計每一本書的作者個數
ret = Book.objects.annotate(authorsNum=Count('authors__name'))
示例三:統計每一本以py開頭的書籍的作者個數
queryResult = Book.objects.filter(title__startswith="Py").annotate(num_authors=Count('authors'))
示例四:統計不止一個作者的圖書
queryResult = Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
示例五:根據一本圖書作者數量的多少對查詢集 QuerySet進行排序
queryResult = Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
示例六:查詢各個作者出的書的總價格
# 按author表的所有欄位 group by queryResult = Author.objects.annotate(SumPrice=Sum("book__price")).values_list("name","SumPrice") print(queryResult)
4、F查詢
在上面所有的例子中,我們構造的過濾器都只是將欄位值與某個常量做比較。如果我們要對兩個欄位的值做比較,那該怎麼做呢?
Django 提供 F() 來做這樣的比較。F()的例項可以在查詢中引用欄位,來比較同一個 model 例項中兩個不同欄位的值。
示例一:查詢評論數大於收藏數的書籍
from django.db.models import F # 匯入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)
5、Q查詢
filter()等方法中的關鍵字引數查詢都是一起進行“AND”的。如果你需要執行更復雜的查詢(例如OR 語句),你可以使用Q 物件。
from django.db.models import Q # 匯入Q函式 Q(title__startswith='Py') # 將要關鍵字查詢條件放入Q方法中
Q 物件可以使用&和|操作符組合起來。當一個操作符在兩個Q物件上使用時,它產生一個新的Q 物件。
示例一:
bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon")) # 上面等同於下面的SQL WHERE子句: WHERE name ="yuan" OR name ="egon"
示例二:你可以組合“&”和“|”操作符以及使用括號進行分組來編寫任意複雜的Q 物件。同時,Q 物件可以使用“~”操作符取反,這允許組合正常的查詢和取反(NOT) 查詢:
booklist = Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")
示例三:查詢函式可以混合使用Q 物件和關鍵字引數。所有提供給查詢函式的引數(關鍵字引數或Q 物件)都將"AND”在一起。但是,如果出現Q 物件,它必須位於所有關鍵字引數的前面。例如:
booklist = Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),title__icontains="python")
二、靜態檔案的設定(測試環境按照如下配置,記住步驟照做即可)
1)在專案目錄下建立static資料夾;
2)專案中用到的靜態資源如圖片,js檔案,bootstrap檔案等放到static中(static中再分別建立img、js、bootstrap、css資料夾用於存放這些檔案);
3)在專案的settings.py檔案中,STATIC_URL = "/static/" 下邊加上如下程式碼:
STATICFILES_DIRS = [ os.join.path(BASE_DIR, "static") ]