一篇文章帶你了解Django ORM操作(高端篇)
前言
上次兩篇基本學(xué)完的Django ORM各種操作,怎么查,各種查。感興趣的小伙伴可以戳這兩篇文章學(xué)習(xí)下,一篇文章帶你了解Django ORM操作(進(jìn)階篇)、一篇文章帶你了解Django ORM操作(基礎(chǔ)篇)。
但是還是遺留了一些技能。,再來(lái)瞅瞅吧!
查詢
聚合操作
聚合操作,不要被名字嚇到了,通常用在篩選完一些數(shù)據(jù)之后,求一下平均值了,什么的。
例如:求所有書的總價(jià)格和平均價(jià)格
原生sql
- SELECT
 - SUM(price) AS "所有書總價(jià)格",
 - avg(price) AS "所有書平均價(jià)格"
 - FROM
 - web_book;
 
T SUM(price) AS "所有書總價(jià)格", avg(price) AS "所有書平均價(jià)格"FROMweb_book;
執(zhí)行結(jié)果

ORM
- price = models.Book.objects.all().aggregate(Sum("price"),Avg("price"), )
 - print(price)
 
執(zhí)行結(jié)果

可以發(fā)現(xiàn)和上面是一樣的,但是會(huì)發(fā)現(xiàn)列名是默認(rèn)是字段__聚合函數(shù)名。
原生sql是可以指定顯示的列名的,同樣,ORM也可以。
代碼
- # 需要導(dǎo)入的包
 - from django.db.models import Avg,Sum
 - price = models.Book.objects.all().aggregate(所有書總價(jià)格=Sum("price"), 所有書平均價(jià)格=Avg("price"), )
 - print(price)
 
執(zhí)行結(jié)果

注:price的類型直接就是dict,所以,在這是不能查看原生sql的。
但是上述ORM對(duì)應(yīng)的原生SQL確實(shí)如上,所以那樣理解就行了。
分組操作
分組操作,就是將某一列,相同的值進(jìn)行壓縮,然后就可以得出壓縮值的數(shù)量。
如果壓縮的是外鍵,還可以取出外鍵的詳細(xì)信息。
示例:查詢出每個(gè)出版社出版的數(shù)量。
通過(guò)研究表結(jié)構(gòu)發(fā)現(xiàn),每出版的書,都在book表中記錄,并且每本書會(huì)外鍵一個(gè)出版社id。

如果我們能對(duì)出版社id進(jìn)行壓縮,然后再求出壓縮出版社id里面對(duì)應(yīng)的數(shù)量。
嘖嘖,這不就出來(lái)了嗎?
代碼
- from django.db.models import Count
 - ret = models.Book.objects.values("publish_id").annotate(publish_count=Count("publish_id"))
 - print(ret)
 
執(zhí)行結(jié)果

原生sql
- SELECT
 - `web_book`.`publish_id`,
 - COUNT(`web_book`.`publish_id`) AS `publish_count`
 - FROM
 - `web_book`
 - GROUP BY
 - `web_book`.`publish_id`;
 
ORM分組和原生SQL對(duì)應(yīng)圖
這一塊,我記得當(dāng)初我迷茫了一段時(shí)間,主要是不知道如何和原生SQL對(duì)應(yīng)上,根據(jù)多次測(cè)試經(jīng)驗(yàn),對(duì)應(yīng)圖如下。

分組獲取外鍵字段信息
上述確實(shí)可以通過(guò)分組實(shí)現(xiàn)了功能。
但是上述只能獲取出版社id,并不能獲取出版社名啥的,但是如何獲取壓縮外鍵字段詳細(xì)信息呢?
代碼
- ret = models.Book.objects.values("publish_id").annotate(publish_count=Count("publish_id")).values("publish__title","publish__phone","publish_count")
 - print(ret)
 
執(zhí)行結(jié)果

注:分組(annotate)后面跟的values。
里面只能寫外鍵字段的列和annotate里面的列,不能寫其他。
如果分組分的不是外鍵字段,那就不能再跟values!
分組再篩選
分組再篩選本質(zhì)就是原生sql的group by .. having,將壓縮完的數(shù)據(jù)在進(jìn)行條件判斷。
但是對(duì)壓縮的數(shù)據(jù)進(jìn)行判斷只能通過(guò)having。
示例:查詢出版社出版的書大于2本的數(shù)據(jù)。
代碼
- ret = models.Book.objects.values("publish_id") \
 - .annotate(publish_count=Count("publish_id")) \
 - .filter(publish_count__gt=2)
 - print(ret)
 
執(zhí)行結(jié)果

F查詢
有時(shí)候,我們可能有這樣的需求,就是兩個(gè)列之間進(jìn)行比較。
比如經(jīng)典問(wèn)題,一個(gè)商品,找到收藏?cái)?shù)大于銷量的商品等之類的兩列進(jìn)行比較的需求。
示例:查詢book表,評(píng)論數(shù)小于收藏?cái)?shù)的數(shù)據(jù)。
代碼
- from django.db.models import F
 - book = models.Book.objects.filter(comment_num__lt=F("collect_num"))
 - print(book)
 
實(shí)際結(jié)果

執(zhí)行結(jié)果

F對(duì)象還支持加減乘除后的比較
示例:評(píng)論數(shù)小于兩倍收藏?cái)?shù)的數(shù)據(jù)。
代碼
可是*,也可以是-,+,÷
- from django.db.models import F
 - book = models.Book.objects.filter(comment_num__lt=F("collect_num")*2)
 - print(book)
 
執(zhí)行結(jié)果

F對(duì)象還適用于更新
代碼
- models.Book.objects.all().update(price=F("price")+30)
 
Q查詢
通常情況下,我們使用的filter(條件1,條件2,...),執(zhí)行的都是and查詢。
但是通常一些時(shí)候,我們需要執(zhí)行or查詢。
比如book表,查詢title=<<大明帝國(guó)>> or title=<<安史之亂>>的。
這時(shí)候,如果使用Django ORM,就只能使用Q查詢構(gòu)建條件。
代碼
- from django.db.models import Q
 - books = models.Book.objects.filter(Q(title="<<大明帝國(guó)>>") | Q(title="<<安史之亂>>"))
 - print(books)
 
執(zhí)行結(jié)果

注:|是or的意思,&是and的意思。
所以,如果將上述的|換成&,filter(條件1,條件2,...)一個(gè)意思,還是and。
Q查詢之~
~相當(dāng)于not。
示例:查詢title = "<<大明帝國(guó)>>" or title != "<<安史之亂>>"。
代碼
- from django.db.models import Q
 - books = models.Book.objects.filter(Q(title="<<大明帝國(guó)>>") | ~Q(title="<<安史之亂>>"))
 - print(books)
 
執(zhí)行結(jié)果

Q查詢和and混合查詢
Q查詢和and查詢同時(shí)出現(xiàn),Q查詢必須在其他查詢之前。
示例:查詢title = "<<大明帝國(guó)>>" or title != "<<安史之亂>>" 并且publish_id=1的。
代碼
- from django.db.models import Q
 - books = models.Book.objects.filter(Q(title="<<大明帝國(guó)>>") | ~Q(title="<<安史之亂>>"),publish_id=1)
 - print(books)
 
執(zhí)行結(jié)果

動(dòng)態(tài)構(gòu)造Q查詢
一些時(shí)候,我們可能并不太確定有什么條件。
可能是動(dòng)態(tài)傳的,傳過(guò)來(lái)多少,就拼接多少。
Q查詢,就能做到這個(gè),在做動(dòng)態(tài)Q查詢時(shí),動(dòng)態(tài)Q不僅支持or,還支持and。
示例:查詢publish_id=1或者title模糊=大明 的書。
代碼
- q = Q()
 - # 查詢方式,or還是and
 - q.connector = "or" # or,and
 - # publish_id=1
 - q.children.append(("publish_id", "1"))
 - # title__contains="大明"
 - q.children.append(("title__contains", "大明"))
 - books = models.Book.objects.filter(q)
 - print(books)
 
執(zhí)行結(jié)果

增
上面說(shuō)了那么多,終于算是大概說(shuō)完了,來(lái)簡(jiǎn)單看一下怎么添加一條數(shù)據(jù)吧。
示例:添加一本書
代碼
方式一,通過(guò)objects.create。
這種方式用的最多。
- models.Book.objects.create(
 - title="<<人類簡(jiǎn)史2>>",
 - price=66.66,
 - PublishDate="2020-01-02",
 - comment_num=23,
 - collect_num=12,
 - # 外鍵字段 django models對(duì)應(yīng)的mysql 為 字段_id
 - publish_id=1,
 - # publish字段需要是一個(gè) Publish 對(duì)象
 - # publish=models.Publish.objects.filter(id=1)
 - )
 
方式二,通過(guò)model對(duì)象.save()。
- book_obj = models.Book(
 - title="<<人類簡(jiǎn)史2>>",
 - price=66.66,
 - PublishDate="2020-01-02",
 - comment_num=23,
 - collect_num=12,
 - # 外鍵字段 django models對(duì)應(yīng)的mysql 為 字段_id
 - publish_id=1, )
 - book_obj.save()
 
方式三,通過(guò)字典方式。
可能有的時(shí)候,我們正好將傳過(guò)來(lái)的參數(shù)構(gòu)造成了一個(gè)字典,那就太好了,不需要再一個(gè)個(gè)取。
- c_dict = {
 - "title":"<<tcp編程從入門到精通2>>",
 - "price":88.1,
 - "PublishDate":"2020-01-03",
 - "comment_num":13,
 - "collect_num":78,
 - "publish_id":1,
 - }
 - models.Book.objects.create(**c_dict)
 
更新
注:update只能跟在在filter之后。
示例:將title="<<大明帝國(guó)>>"的數(shù)據(jù)修改為title="<<大明帝國(guó)666>>"。
代碼
- models.Book.objects.filter(title="<<大明帝國(guó)>>").update(title="<<大明帝國(guó)666>>")
 
filter可能篩選到的是多個(gè)值,一定要注意
刪除
delete只能跟在filter之后。
示例:刪除title=<<大明帝國(guó)666>>的數(shù)據(jù)。
- models.Book.objects.filter(title="<<大明帝國(guó)666>>").delete()
 
總結(jié)
好了各位,到此為止,基本上,Django ORM操作基本完畢,至少80%的知識(shí)都覆蓋完畢。
本篇主要補(bǔ)充的是一些高端操作,例如聚合操作,分組操作,分組再篩選操作,F查詢和Q查詢。
如何動(dòng)態(tài)構(gòu)造Q查詢。
相對(duì)來(lái)說(shuō),Django還是自由度比價(jià)高的,而且寫起來(lái)確實(shí)比較省心。
用微笑告訴別人,今天的我比昨天強(qiáng),今后也一樣。
















 
 
 





 
 
 
 