本篇筆記將介紹 update 和 create 的一些其他用法,目錄如下:
- get_or_create
- update_or_create
- select_for_update
- bulk_create
- bulk_update
1、get_or_create
前面我們介紹過 get() 和 create() 的用法,那么 get_or_create() 的意思很簡單,就是 獲取或者創建,如果存在就回傳,不存在就先創建再回傳,
假設對于 Blog model,我們想看下資料庫有沒有 name="hunter", tagline="tagline_test" 的資料,沒有的話創建并獲取這條資料,有的話,就直接獲取,
在之前我們操作可能是:
try:
blog = Blog.objects.get(name='hunter', tagline='tagline_test')
except Blog.DoesNotExist:
blog = Blog(name='hunter', tagline='tagline_test')
blog.save()
現在我們可以直接這樣操作:
blog, created = Blog.objects.get_or_create(name='hunter', tagline='tagline_test')
這個函式的回傳值有兩個,一個是操作的 model 實體,一個是是否是 created 的 布爾型資料,
created 為 True,表示這條資料是創建,create() 到的
created 為 False,表示這條資料是獲取, get() 到的
注意: 查詢的條件必須是唯一的,否則會造成多條資料回傳而報錯,這個邏輯同 get() 函式,
注意: 使用的欄位,沒有唯一的約束,并發的呼叫這個方法可能會導致多條相同的值插入,
欄位默認值
假設 Blog 這個 model 除了 name, tagline 這兩個欄位外,還有 field_1 和 field_2 欄位,但是他們不在我們查詢的條件內,作用為在創建的時候設定的默認值,我們可以通過 defaults 來操作:
blog, created = Blog.objects.get_or_create(
name='hunter',
tagline='tagline_test',
defaults={
'field_1': 'field_1_value',
'field_2': 'field_2_value'
}
)
最后關于這個函式,有個小提示,如果這個函式用在介面里,那么根據冪等性,我們應該使用 POST 方法來請求,而不是 GET 請求,
關于冪等性的概念,有興趣的話可以去查詢一下,
2、update_or_create
更新或者創建,使用方法同 get_or_create()
假設對于 Blog model 我們想實作的操作如果存在 name='hunter', tagline='tagline_test' 的資料就將其 field_1 和 field_2 的欄位更新,不存在的話,就創建該資料,
之前的操作邏輯大概如下:
defaults = {"field_1": "field_1_value", "field_2": "field_2_value"}
try:
obj = Blog.objects.get(name='hunter', tagline='tagline_test')
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except:
new_values = {"name": "hunter", "tagline": "tagline_test}
new_values.update(defaults)
obj = Blog(**new_values)
obj.save()
現在我們使用 update_or_create 可以如下操作:
obj, created = Blog.objects.update_or_create(
name='hunter', tagline='tagline_test',
defaults={"field_1": "field_1_value", "field_2": "field_2_value"}
)
3、select_for_update
select_for_update 的操作復雜一點,作用類似于 SQL 中的 SELECT ... FOR UPDATE 陳述句
操作如下:
from django.db import transaction
blog_list = Blog.objects.select_for_update().filter(name="hunter")
with transaction.atomic():
for blog in blog_list:
...
當 blog_list 去獲取資料的時候,所有匹配上的 entries 都會被鎖,直到這個事務結束,
意味著這個時候,其他的事務會被阻止更改或者重新在這些資料上加鎖,
我們來舉個例子,在我們執行下面的陳述句時:
import time
from django.db import transaction
blog_list = Blog.objects.select_for_update().filter(name="hunter")
with transaction.atomic():
for blog in blog_list:
print("locking ...")
time.sleep(20)
這個時候,我們在重新開一個 shell,來執行下面的陳述句:
Blog.objects.filter(name="hunter").update(name="hunter_1")
因為第一個 shell 里執行的命令還沒有結束,而且在資料上加了鎖,因此第二個 shell 里的陳述句會進入等待,直到第一個 shell 里的命令執行完成之后,第二個 shell 里的命令才會執行,
注意: 如果在第一個命令里,對 blog 資料進行操作,比如 把 name 欄位改為了 hunter_2,那么在第二條命令的條件里篩選不到結果然后更新的,
4、bulk_create
批量創建,在前面介紹增刪改查的時候介紹過一次,這里再簡單做一下示例:
from blog.models import Blog
blog_list = [
Blog(name="hunter_1", tagline="tag_1"),
Blog(name="hunter_2", tagline="tag_2"),
Blog(name="hunter_3", tagline="tag_3"),
Blog(name="hunter_4", tagline="tag_4")
]
Blog.objects.bulk_create(blog_list)
如果我們批量創建的數量過多,我們可以指定分批次來創建,通過 batch_size 引數來指定,
Blog.objects.bulk_create(blog_list, batch_size=2)
5、bulk_update
批量更新,方式與 bulk_create 的方式類似,以下是使用示例:
blog_list = Blog.objects.filter(id__lte=20)
for blog in blog_list:
blog.name = "name_updated"
blog.tagline = "tag_updated"
Blog.objects.bulk_update(blog_list, fields=['name'], batch_size=2)
需要注意的是 bulk_update 多了個引數,fields 這個是用來指定需要更新的欄位,
如我們上面的命令所示,我們指定更新的是 name 欄位,那么就算我們更改了 tagline 的資料,只要 fields 串列里沒有指定該欄位,那么后臺也不會更新該欄位,
以上就是本篇筆記全部內容,接下來我們將介紹一下查詢中的其他用法,比如latest,first,contains 等,
本文首發于本人微信公眾號:Hunter后端
原文鏈接:Django筆記十三之select_for_update等選擇和更新等相關操作
如果想獲取更多相關文章,可掃碼關注閱讀:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/548902.html
標籤:其他
