Django常用的QuerySet操作
1. 支援鏈式呼叫的介面
-
all
使用頻率比較高,相當於SELECT * FROM table 語句,用於查詢所有資料。
-
filter
使用頻率比較高,根據條件過濾資料,常用的條件基本上欄位等於、不等於、大於、小於。當然,還有其他的,比如能修改成產生LIKE查詢的:Model.objects.filter(content__contains="條件")。
-
exclude
與filter是相反的邏輯
-
reverse
將QuerySet中的結果倒敘排列
-
distinct
用來進行去重查詢,產生SELECT DISTINCT這樣的SQL查詢
-
none
返回空的QuerySet
2. 不支援鏈式呼叫的介面
-
get
比如Post.objects.get(id=1)用於查詢id為1的文章:如果存在,則直接返回對應的Post例項;如果不存在,則丟擲DoesNotExist異常。所以一般情況下,要使用異常捕獲處理:
1 try:
2 post = Post.objects.get(id=1)
3 except Post.DoesNotExist:
4 #做異常情況處理
-
create
用來直接建立一個Model物件,比如post = Post.objects.create(title="一起學習")。
-
get_or_create
根據條件查詢,如果沒查詢到,就呼叫create建立。
-
update_or_create
與get_or_create相同,只是用來做更新操作。
-
count
用於返回QuerySet有多少條記錄,相當於SELECT COUNT(*) FROM table 。
-
latest
用於返回最新的一條記錄,但要在Model的Meta中定義:get_latest_by= <用來排序的欄位>。
-
earliest
同上,返回最早的一條記錄。
-
first
從當前QuerySet記錄中獲取第一條。
-
last
同上,獲取最後一條。
-
exists
返回True或者False,在資料庫層面執行SELECT (1) AS "a" FROM table LIMIT 1的查詢,如果只是需要判斷QuerySet是否有資料,用這個介面是最合適的方式。
不要用count或者len(queryset)這樣的操作來判斷是否存在。相反,如果可以預期接下來會用到QuerySet中的資料,可以考慮使用len(queryset)的方式來做判斷,這樣可以減少一次DB查詢請求。
-
bulk_create
同create,用來批量建立記錄。
-
in_ bulk
批量查詢,接收兩個引數id_ list和filed_ name。可以通過Post.objects. in_ bulk([1, 2, 3])查詢出id為1、2、3的資料,返回結果是字典型別,字典型別的key為查詢條件。返回結果示例: {1: <Post 例項1>, 2: <Post例項2>,3:<Post例項3>}。
-
update
用來根據條件批量更新記錄,比如: Post.objects.filter(owner__name='123').update(title='測試更新')。
-
delete
同update,這個介面是用來根據條件批量刪除記錄。需要注意的是,和delete都會觸發Djiango的signal
-
values
當我們明確知道只需要返回某個欄位的值,不需要Model例項時,用它,用法如下:
1 title_list = Post.objects.filter(category_id=1).values('title')
返回的結果包含dict的QuerySet,類似這樣: <QuerySet [{'title' :xxx},]>
-
values_list
同values,但是直接返回的是包含tuple的QuerySet:
1 titles_list = Post.objects.filter(category=1).values_list('title')
返回結果類似: <QuerySet[("標題",)]>
如果只是一個欄位的話,可以通過增加flat=True引數,便於我們後續 處理:
1 title_list = Post.objects.filter(category=1).values_list('title',flat=True)
2 for title in title__list:
3 print(title)
2.1進階介面
除了上面介紹的常用介面外,還有其他用來提高效能的介面,在下面介紹。 在優化Django專案時,尤其要考慮這幾種介面的用法。
-
defer
把不需要展示的欄位做延遲載入。比如說,需要獲取到文章中除正文外的其他欄位,就可以通過posts = Post.objects.all() .defer('content'),這樣拿到的記錄中就不會包含content部分。但是當我們需要用到這個欄位時,在使用時會去載入。程式碼:
1 posts = Post.objects.all().defer('content')
2 for post in posts: #此時會執行資料庫查詢
3 print (post.content) #此時會執行資料查詢,獲取到content
當不想載入某個過大的欄位時(如text型別的欄位),會使用defer,但是上面的演示代產生N+1的查詢問題,在實際使用時千萬要注意!
注意:上面的程式碼是個不太典型的 N+1查詢的問題, 一般情況下 由外來鍵查詢產生的N+1問題比較多,即一條查詢請求返回N條資料,當我們運算元據時,又會產生額外的請求。這就是N+1問題,所有的ORM框架都存在這樣的問題。
-
only
同defer介面剛好相反, 如果只想獲取到所有的title記錄,就可以使用only,只獲取title的內容,其他值在獲取時會產生額外的查詢。
-
select_related
這就是用來解決外來鍵產生的N+1問題的方案。我們先來看看什麼情況下會產生這個問題:
posts = Post.objects.all ()
for post in posts: #產生資料庫查詢
print (post.owner) #產生額外的資料庫查詢
程式碼同上面類似,只是這裡用的是owenr(是關聯表)。它的解決方法就是用select_ related介面:
post = Post.objects.all() .select_related('category')
for post in posts: # 產生資料庫查詢,category資料也會一次性查詢出來
print (post.category)
當然,這個介面只能用來解決一對多的關聯關係。對於多對多的關係,還得使用下面的介面。
-
prefetch_related
針對多對多關係的資料,可以通過這個介面來避免N+1查詢。比如,post和tag的關係可以通過這種方式來避免:
posts = Post.objects.all().prefetch_related('tag')
for post in posts:#產生兩條查詢語句,分別查詢post和tag
print(post.tag.al1())
3.常用的欄位查詢
-
contains
包含,用來進行相似查詢。
-
icontains
同contains,只是忽略大小寫。
-
exact
精確匹配。
-
iexact
同exact,忽略大小寫。
-
in
指定某個集合,比如Post.objects.filter(id__in=[1, 2, 3])相當於SELECT FROM table WHERE IN (1, 2, 3);。
-
gt
大於某個值。比如:Post.objects.filter(id__gt=1)
注意:是__gt
-
gte
大於等於某個值。
-
lt
小於某個值。
-
lte
小於等於某個值。
-
startswith
以某個字串開頭,與contains類似,只是會產生LIKE '<關鍵詞>%'這樣的SQL。
-
istartswith
同startswith, 忽略大小寫。
-
endswith
以某個字串結尾。
-
iendswith
同endswith,忽略大小寫。
-
range
範圍查詢,多用於時間範圍,如Post.objects.filter(created_time__range= ('2018-05-01','2018-06-01'))會產生這樣的查詢: SELECT .. . WHERE created_ time BETWEEN '2018-05-01' AND '2018-06-01' ;。
關於日期類的查詢還有很多,比如date、year和month等,具體等需要時查文件即可。
這裡你需要理解的是,Django之所以提供這麼多的欄位查詢,其原因是通過ORM來運算元據庫無法做到像SQL的條件查詢那麼靈活。
因此,這些查詢條件都是用來匹配對應SQL語句的,這意味著,如果你知道某個查詢在SQL中如何實現,可以對應來看Django提供的介面。
3.1 進階查詢
除了上面基礎的查詢語句外,Django還提供了其他封裝,來滿足更復雜的查詢,比如 SELECT ... WHERE id = 1 OR id = 2 這樣的查詢,用上面的基礎查詢就無法滿足。
-
F
F表示式常用來執行資料庫層面的計算,從而避免出現競爭狀態。比如需要處理每篇文章的訪問量,假設存在post.pv這樣的欄位,當有使用者訪問時,我們對其加1:
post = Post.objects.get(id=1)
post.pv = post.pv+1
post.save()
這在多執行緒的情況下會出現問題,其執行邏輯是先獲取到當前的pv值,然後將其加1後賦值給post .pv.最後儲存。
如果多個執行緒同時執行了post = Post.objects.get(id=1),那麼每個執行緒裡的post .pv值都是一樣的, 執行完加1和儲存之後,相當於只執行了一個加1,而不是多個。
這時通過F表示式就可以方便地解決這個問題:
from ajango.ab. models import F
post = Post.objects.get(id=1)
post.pv = F('pv') + 1
post.save():
這種方式最終會產生類似這樣的SQL語句: UPDATE table SET pv = pv +1 WHERE ID = 1。 它在資料庫層面執行原子性操作。
-
Q
Q表示式就是用來解決前面提到的那個OR查詢的,可以這麼用:
from django.db.mode1s import Q
Post.objects.filter(Q(id=1) | Q(id=2))
或者進行AND查詢:
Post.objects.filter(Q(id=1) & Q(id=2))
-
Count
用來做聚合查詢,比如想要得到某個分類下有多少篇文章,簡單的做法就是:
category = Category.objects.get(id=1)
posts_count = category.post_set.count()
但是如果想要把這個結果放到category上呢?通過category.post_count可以訪問到:
from django.db.models import Count
categories = Category.objects.annotate(posts_count=Count('post'))
print(categories[0].posts_count)
這相當於給category動態增加了屬性post_count,而這個屬性的值來源於Count('post'),最後可以用int取整。
-
Sum
同Count類似,只是它是用來做合計的。比如想要統計所有資料欄位的總和,可以這麼做:
from django.db.models import Sum
Post.objects.all().aggregate(a=Sum('欄位'))
#輸出類似結果:{'a':487}為字典
python中對字典中鍵值對的獲取:
for i in book:
print(i)#鍵的獲取
print(book[i])#值的獲取
上面演示了QuerySet的annotate和aggregate的用法,其中前者用來給QuerySet結果増加屬性,後者只用來直接計算結果,這些聚合表示式都可以與它們結合使用。
除了Count和Sum外,還有Avg、Min和Max等表示式,均用來滿足我們對SQL査洵的需求。
相關文章
- Django中的QuerySetDjango
- Django ORM QuerySetDjangoORM
- Django(19)QuerySet APIDjangoAPI
- [轉] 高效使用 django 的 querysetDjango
- Django 2.0 模型層中 QuerySet 查詢操作介紹Django模型
- Django學習筆記(13)——Django的使用者認證元件,檢視層和QuerySet APIDjango筆記元件API
- Django(33)Django操作cookieDjangoCookie
- django模型操作Django模型
- KVM的常用操作
- Promethues的常用操作
- Netty的常用操作Netty
- Django ORM 多表操作DjangoORM
- 深入理解Django的ModelForm操作DjangoORM
- Django 常用的自定義裝飾器Django
- Django Model各種操作 Meta 常用欄位 一對多操作 多對對操作 F Q查詢 聚合函式Django函式
- 熟悉常用的Linux操作和Hadoop操作LinuxHadoop
- Django ORM 單表操作DjangoORM
- django 模板語言的註釋操作Django
- Django(31)模板中常用的過濾器Django過濾器
- MongoDB的常用Query操作及操作符MongoDB
- mysql常用的優化操作MySql優化
- JavaScript操作DOM常用的APIJavaScriptAPI
- 常用的JavaScript位操作(Bitwise)JavaScript
- 命令列中的常用操作命令列
- 我的常用tmux操作命令UX
- django操作多資料庫Django資料庫
- django多資料庫操作Django資料庫
- Django之ORM連表操作DjangoORM
- Django-ORM-單表操作DjangoORM
- DOM常用操作
- git常用操作Git
- MySQL 常用操作MySql
- vim常用操作
- 常用git操作Git
- Hive 常用操作Hive
- git 常用操作Git
- nerdctl 常用操作
- 常用sql 操作SQL