Django - 覆盖模型保存()
Posted
技术标签:
【中文标题】Django - 覆盖模型保存()【英文标题】:Django - Override model save() 【发布时间】:2018-10-07 14:50:04 【问题描述】:在我们的项目中,我们使用软删除(模型上的 is_deleted 属性)。 在创建新模型之前,我想首先检查它是否已经存在并被删除,如果是 - 设置 is_deleted=False 并保存已经存在的模型。 所以我决定重写模型的“保存”方法。 (不是 View Create,因为它不仅适用于请求) 问题是所有操作(创建、更新、删除)都调用了“save()”。 有没有办法只在创建时调用被覆盖的方法?
class Model(BaseModel):
title = models.CharField(max_length=200)
identifier = models.CharField(max_length=15)
def save(self, *args, **kwargs):
try:
existing_model = Model.objects.active_and_deleted().get( identifier=self.identifier)
if self.is_deleted is False:
existing_model.is_deleted = False
existing_model.title = self.title
existing_model.created_at = self.created_at
existing_model.updated_at = self.updated_at
existing_model.created_by = self.created_by
existing_model.deleted_at = None
super(Model, existing_model).save(args, kwargs)
except Model.DoesNotExist:
# in case the Nodel wasn't already exist - continue
pass
super(Model, self).save(*args, **kwargs)
【问题讨论】:
您想在重新插入之前“删除”记录吗?为什么? 所以实际上你在你的数据库中没有删除任何东西!您处理所有具有is_deleted=False
的对象。当有人删除某些内容时,您只需将 is_deleted
设置为 True。对吗?
@Lemayzeur - 是的。
在创建新模型之前,我想先检查它是否已经存在。为此,您需要一个字段作为比较来测试对象是否已经存在,例如:您可以检查title
【参考方案1】:
您的问题的答案,“有没有一种方法可以只在创建时调用被覆盖的方法?”这是:
def save(self, *args, **kwargs):
if not self.id:
# Object is a new instance
return super(Model, self).save(*args, **kwargs)
但这里还有其他问题。例如,您的模型不应命名为“模型”。
【讨论】:
谢谢,但第一次进入保存功能时它确实有 id。我正在使用 Model.objects.create(...) 来测试它。 我认为你错了。如果该项目尚未创建,那么它将没有id
或pk
。这是 ORM 工作方式的核心组件。
当“对象有一个 UUIDField 作为它的主键”时,该答案适用。您似乎没有这样做,或者手动设置pk
。你是吗?
代替“if not self.id”,尝试“if self._state.adding”。
@PaulTuckett - 使用 self._state.adding 的另一个原因是如果您使用模型字段关键字“primary_key”。在这种情况下,self 没有“id”属性,并且 self.pk 甚至在模型保存之前就被分配了一个值。【参考方案2】:
检查 self.pk
是否为 None 是否可以做你想做的事,这里是一个例子:
class ModelName(mdoels.Model):
title = models.CharField(max_length=200)
identifier = models.CharField(max_length=15)
def save(self, *args, **kwargs):
if self.pk is None: # Adding of a new instance
# let's say we compare instances by `title`
# you can use other fields for the comparison
possible_old_instance = Model.objects.filter(title__iexact=self.title)
if possible_old_instance.exists():
existing_model = possible_old_instance.first()
existing_model.is_deleted = False
existing_model.title = self.title
existing_model.created_at = self.created_at
existing_model.updated_at = self.updated_at
existing_model.created_by = self.created_by
existing_model.deleted_at = None
existing_model.save()
# Nothing happens, we don't call save() method
else:
# in case the Model doesn't exist
super(ModelName, self).save(*args, **kwargs)
else:
super(ModelName, self).save(*args, **kwargs)
【讨论】:
我的项目 self.pk 也已经设置为一个新实例。但我会使用自我的不同属性来识别不同的行为。谢谢 您可以这样做,使用self.pk
或 self.id
... 这些属性仅在调用 save()
时返回非空 None
值【参考方案3】:
如果您使用 UUID 字段而不是默认 ID 字段,检查 self.pk 字段是一个糟糕的主意,因为在我们转到 save 方法之前将 UUID 指定为默认值。嗯,怎么解决呢?最简单最快的解决方案是 self._state.adding 而不是 self.pk
我希望你注意到“状态”这个词之前有一个下划线,但别担心,这个方法是完全合法的,我们这里不叫私有变量。
例子:
def save(self, *args, **kwargs):
if self._state.adding: # will return true if obcject is newly created
# Object is a new instance
return super(Model, self).save(*args, **kwargs)
【讨论】:
以上是关于Django - 覆盖模型保存()的主要内容,如果未能解决你的问题,请参考以下文章
保存自定义用户模型时 Django ManyToMany 覆盖
使用覆盖保存为抽象模型扩展 Django ModelForm