本文首發於微信公眾號:Hunter後端
這篇筆記主要介紹 Django 一些例項方法。
什麼是 例項,我們知道透過filter() 的一些篩選方法,得到的是 QuerySet,而 QuerySet 取單條資料,透過索引,或者 first() 或者 last() 等方法,得到的單條資料,就是一個 model 的例項。
我們接下來要介紹的就是這種單條例項的一些方法。
- save() 的繼承操作
- refresh from db, 從資料庫中更新例項資料
- 自增的主鍵
- 指定欄位更新 save()
1、save() 的繼承操作
對於一個 model,我們可以透過 save() 的方式建立一條資料,比如:
from blog.models import Blog
blog = Blog(name="blog_1", tagline="tagline_1")
blog.save()
對於上面的 blog,我們就稱其為 Blog 的一個例項。
我們可以透過繼承覆蓋原有的 save() 方法,然後新增一些我們需要的操作,比如列印日誌,傳送提醒等。
方法如下:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
print("save")
super(Blog, self).save(*args, **kwargs)
這樣,我們在對 Blog 資料進行 save() 操作的時候,就可以看到控制檯會輸出 "save" 的記錄。
除此之外,Django 的文件提出了一種方式,在 model 中定義一個類方法,可以方便我們對資料進行處理:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
@classmethod
def create(cls, name, tagline):
blog = cls(name=name, tagline=tagline)
print("get an unsaved Blog instance")
return blog
然後透過呼叫該方法,傳入引數,可以得到一個未儲存的例項:
from blog.models import Blog
blog = Blog.create(name='test_create', tagline='test_tagline')
blog.save()
注意: 在我們執行 create() 方法的時候,程式還沒有運算元據庫,只是得到一個未儲存的例項,我們仍然需要執行 save() 操作才能儲存到資料庫。
除了這種方法,還有一種官方文件更推薦的方法,就是使用 manager,這個的用法我們在後面幾篇筆記中涉及,這裡只做一個展示:
class BlogManager(models.Manager):
def create_blog(self, name, tagline):
blog = self.create(name=name, tagline=tagline)
# do something with the blog
print("get an unsaved Blog instance")
return blog
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
objects = BlogManager()
需要注意的是,這裡呼叫的是 create() 方法,所以直接儲存到了資料庫,不用再執行 save() 方法了。
2、refresh from db, 從資料庫中更新例項資料
方法為 refresh_from_db()
作用為從資料庫中獲取例項資料的最新值。
blog = Blog.objects.first()
# 其他地方可能會對 blog 資料進行一些更改
# 然後從資料庫中拉取 blog 的最新資料
blog.refresh_from_db()
這個操作我個人常常用在寫單元測試,比如經過一系列操作之後,想要檢視這個 obj 的資料有沒有更改,這種情況下就可以使用這個函式。
說一下 refresh_from_db() 這個函式的效能問題,refresh_from_db() 的底層函式也是使用的 get() 方法
所以使用 refresh_from_db() 和 get(pk=xx) 這兩者在效能上可能差別不會很大,但是 refresh_from_db() 則更為簡潔。
3、自增的主鍵
如果我們沒有為 model 設定 PrimaryKey,那麼系統則會自動為 model 設定自增主鍵為 id 的欄位,建立資料的時候,不指定該欄位,系統會自動為其賦值。
而當我們想要複製一條資料記錄的時候,我們可以將 id 欄位置為 None,然後 save(),系統則會將其視為一條新資料,從而自動儲存為新資料併為 id 欄位賦值。
b = Blog.objects.first()
b.id = None
b.save()
b.id
4、指定欄位更新 save()
假設有一個 TestModel,有一個 number 欄位,我們想要對其執行 +1 的操作,大概行為可能如下:
obj = TestModel.objects.get(id=1)
obj.number += 1
obj.save()
我們也可以透過 F() 函式這種稍微快一點和避免競爭的方式(競爭的意思是,其他的程式可能也在使用這條資料):
from django.db.models import F
obj = TestModel.objects.get(id=1)
obj.number = F('number') + 1
obj.save()
指定欄位儲存
單純的使用 save() 操作可能會造成一個問題,比如說,我們在某一個 get 了一條資料,對 name 欄位進行了更改,但同時另一個程式對同一條資料也進行了更改,我們對這條資料進行 save() 操作,那麼就可能造成資料不一致的情況。
blog = Blog.objects.get(id=1)
blog.name = "test_1"
# 在這個期間,另一個程式對 tagline 欄位進行了更改
# 假設該操作為 Blog.objects.filter(id=1).update(tagline="new_tagline")
# 然後執行 save() 操作
blog.save()
那麼這個時候,blog 的資料因為已經從資料庫中獲取了出來,再執行 save() 則會儲存之前獲取的資料,這樣會導致在此期間對 tagline 欄位進行的更新操作還原。
那麼這個時候,為了避免這種情況發生,我們在 save() 的時候指定我們要更新的欄位來儲存資料:
blog.name = "test_1"
blog.save(update_fields=["name"])
以上就是本篇筆記全部內容,下一篇筆記將介紹 manager 的用法。
如果想獲取更多相關文章,可掃碼關注閱讀: