在django
中,我們有時候需要自己控制數據庫的存儲。這就需要我們重寫模型的.save()
方法。
一般來說,我們可以這樣寫:
class Student(models.Model):
username = models.CharField('學生姓名', max_length=16)
age = models.IntegerField('年齡')
def save(self, *args, **kwargs):
do_something()
super().save(*args, **kwargs) # 執行真正的 .save() 方法.
do_something_else()
一、舉個例子,使用do_something_else()
的場景:
我們創建訂單,訂單有一個編號the_id
是根據創建日期和主鍵pk
生成的。
class Order(models.Model):
def _create_the_id(self):
"""生成訂單編號"""
return self.created.date().strftime('%Y%m%d') + '_' + str(self.id)
created = models.DateTimeField('創建時間', auto_now_add=True)
the_id = models.CharField('訂單編號', max_length=32, unique=True, null=True)
title = models.CharField('訂單名稱', max_length=32, default='')
total = models.FloatField('訂單金額', default=0.0)
在這里,我們的the_id
屬性依賴于id
,所以我們必須先執行.save()
然后再進行更新。
>>> order = Order(title='訂單的標題****', total=25.5)
>>> order.save() # 保存進數據庫,獲取 id
>>> order.the_id = order._create_the_id()
>>> order.save() # 更新 the_id 屬性
這里就有一個問題,我們需要在每個.save()
執行后都執行
>>> order.the_id = order._create_the_id()
更好的方法是重寫.save()
方法
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
# 執行 save(), 將數據保存進數據庫
super().save(
force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields
)
self.the_id = self._create_the_id()
# 再次執行 save(), 將數據更新到數據庫
# 注意這里的參數,必須設置 force_update=True,否則會創建新的數據
super().save(
force_insert=False,
force_update=True,
using=using,
update_fields=['the_id']
)
當我們重寫.save()
后,就不用考慮會不會忘記執行更新the_id
操作了。現在直接執行.save()
就會自動幫我們更新the_id
二、在.save()
之前執行do_something()
在數據庫中,有些屬性屬于派生屬性
,也就是說它們是依據其它屬性生成的。
class Order(models.Model):
created = models.DateTimeField('創建時間', auto_now_add=True)
title = models.CharField('訂單名稱', max_length=32, default='')
num = models.IntegerField('商品數量')
price = models.FloatField('商品價格')
total = models.FloatField('訂單金額', default=0.0)
在上述訂單模型
中,total
應該是在后端存儲時自動計算,而不是接收前端傳給我們的數據。
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
self.total = self.num * self.price
# 執行 save(), 將數據保存進數據庫
super().save(
force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields
)