無論對於什麼業務來說,用戶數據信息的安全性無疑都是非常重要的。尤其是在數字經濟大火背景下,數據的安全性就顯得更加重要。數據脫敏可以分為兩個部分,一個是DB層面,防止DB數據泄露,暴露用戶信息;一個是介面層面,有些UI展示需要數據脫敏,防止用戶信息被人刷走了。 v需求背景 DB層面的脫敏今天先不講,今 ...
本篇筆記將介紹 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等選擇和更新等相關操作
如果想獲取更多相關文章,可掃碼關註閱讀: