django系列5.5--分組查詢,聚合查詢,F查詢,Q查詢,腳本中調用django環境

一.聚合查詢

aggregate(*args, **args)python

先引入須要的包,再使用聚合查詢mysql

#計算全部圖書的平均價格
from django.db.models import Avg
Book.objects.all().aggregate(Avg('price'))

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

Book.objects.aggregate(average_price=Avg('price'))
#{'average_price': 34.35}

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

from django.db.models import Avg, Max, Min
Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) 
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}

count('id'),count(1)也能夠統計個數,Book.objects.all().aggregeteBook.objects.aggregate(),均可以 <br/>django

二.分組查詢

annotate()app

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

2.本質是將關聯表join成一張表,再進行單表分組查詢fetch

#查詢每個部門的id以及對應部門員工的平均薪水
models.Emp.objects.values('dep_id').annotate(s = Avg('salary'))

3.annotate()的返回值是queryset,若是不想遍歷對象, 能夠用上valuelistspa

#統計每個出版社的最便宜的書
publishList=Publish.objects.annotate(MinPrice=Min("book__price")) 
for publish_obj in publishList:
    print(publish_obj.name,publish_obj.MinPrice)

若是沒有使用objects後面values或者values_list,獲得的結果是queryset類型,裏面是Publish的model對象,而且是對全部記 錄進行的統計,統計的Minprice也成了這些model對象裏面的一個屬性,這種連表分組統計的寫法最經常使用,思路也比較清晰code

ret=Publish.objects.annotate(MinPrice=Min("book__price")).values_list("name","MinPrice")
print(ret)

執行分組查詢時,務必要將mysql中的ONLY_FULL_GROUP_BY模式關閉,不然分組查詢會有很大概率報錯

1.在mysql目錄下my.ini文件中將sql_mode中的only_full_group_by去掉

2.在mysql中設置sql_mode

#在mysql中查看sql_mode
mysql> select @@global.sql_mode;

#設置sql_mode爲以下操做(去掉ONLY_FULL_GROUP_BY)
mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

緣由:

ONLY_FULL_GROUP_BY的語義就是肯定select target list中的全部列的值都是明確語義,簡單的說來,在ONLY_FULL_GROUP_BY模式下,target list中的值要麼是來自於彙集函數的結果,要麼是來自於group by list中的表達式的值。

<br/>

三.F查詢

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

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

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

Book.objects.filter(commentNum__lt = F('keepNum')*2)

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

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

<br/>

四.Q查詢

1.filter()等方法中的關鍵字參數都是一塊兒進行"AND"的.若是須要OR條件,就可使用Q對象

from django.db.models import Q
Q(title__startswith='Py')

2.q對象可使用&(與), |(或), ~(非) 操做符組合,當一個操做符在兩個Q對象上使用時,產生一個新的Q對象

bookList=Book.objects.filter(Q(authors__name="川端康成")|Q(authors__name="太宰治"))
等同於sql語句:
    WHERE name ="太宰治" OR name ="村上春樹"

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

bookList=Book.objects.filter(Q(authors__name="太宰治") & ~Q(publishDate__year=2017)).values_list("title")
bookList=Book.objects.filter(Q(Q(authors__name="太宰治") & ~Q(publishDate__year=2017))&Q(id__gt=6)).values_list("title") #能夠進行Q嵌套,多層Q嵌套等,其實工做中比較經常使用

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

bookList=Book.objects.filter(
	Q(publishDate__year=2016) | Q(publishDate__year=2017),
    title__icontains="python"  #也是and的關係,可是Q必須寫在前面
)

五.ORM執行原生sql語句

在模型查詢API不夠用的狀況下,還可使用原始的SQL語句進行查詢

Django提供兩種方法使用原始SQL進行查詢:

  1. 使用raw()方法,進行原始SQL查詢並返回模型實例

  2. 徹底避開模型層,直接執行自定義的SQL語句

1.執行原生查詢

  1. raw()管理器方法用於原始的SQL查詢,並返回模型的實例
  2. raw()語法查詢必須包含主鍵
  3. raw()方法自動將查詢字段映射到模型字段.還能夠經過translations參數指定一個把查詢的字段名和ORM對象實例的字段名互相對應的字典

這個方法執行原始的SQL查詢,並返回一個django.db.models.query.RawQuerySet 實例。 這個RawQuerySet 實例能夠像通常的QuerySet那樣,經過迭代來提供對象實例

def query(request):
	for p in models.Book.objects.raw("select * from app01_Book;"):
		print(p) # 這裏的p爲Book object對象
	return HttpResponse('OK')

2.直接執行自定義SQL

須要執行DELETE, INSERT或UPDATE時,能夠直接訪問數據庫,徹底避開模型層

能夠直接從django提供的接口中獲取數據庫鏈接,而後像使用pymysql模塊同樣操做數據庫

from django.db import connection, connections
cursor = connection.cursor()
cursor.execute("select * from auth_user where id = %s ", [1])
ret = cursor.fetchone()

<br/>

六.Python腳本中調用Django環境(django外部腳本使用models)

若是你想經過本身建立的python文件在django項目中使用django的models,那麼就須要調用django環境才能運行

import os
if __name__== '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE","BMS.settings")
import django
django.setup()
			
from app01 import models
			
books = models.Book.objects.all()
print(books)
相關文章
相關標籤/搜索