SpringCloud Eureka-服務註冊與發現01 1.Eureka介紹 1.1學習Eureka前的說明 目前主流的服務註冊&發現的組件是 Nacos,但是 Eureka 作為老牌經典的服務註冊&發現技術還是有必要學習一下,原因: (1)一些早期的分散式微服務項目使用的是 Eureka,在工作 ...
本文首發於微信公眾號: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 的用法。
如果想獲取更多相關文章,可掃碼關註閱讀: