何时在 django 中使用 pre_save、save、post_save?
Posted
技术标签:
【中文标题】何时在 django 中使用 pre_save、save、post_save?【英文标题】:when to use pre_save, save, post_save in django? 【发布时间】:2013-07-12 19:39:53 【问题描述】:我知道我可以覆盖或定义 pre_save, save, post_save
以在保存模型实例时执行我想要的操作。
在什么情况下首选哪一个,为什么?
【问题讨论】:
【参考方案1】:我尽量举例说明:
pre_save
和post_save
是模型发送的signals。简单来说,就是在模型的save
之前或之后采取的行动被调用。
一个save
triggers the following steps
Django 确实提供了一种方法来覆盖这些信号。
现在,
pre_save
信号可以在实际保存到数据库之前被覆盖以进行某些处理 - 示例:(我不知道pre_save
最适合我的最佳示例)
假设您有一个ModelA
,它存储对ModelB
的所有对象的引用,这些对象尚未被编辑。为此,您可以在调用ModelB
的save
方法之前注册pre_save
信号以通知ModelA
(也没有什么能阻止您在这里注册post_save
信号)。
现在,模型的 save
方法(它不是信号)被调用 - 默认情况下,每个模型都有一个 save
方法,但您可以覆盖它:
class ModelB(models.Model):
def save(self):
#do some custom processing here: Example: convert Image resolution to a normalized value
super(ModelB, self).save()
然后,就可以注册post_save
信号了(这个比pre_save
用的多)
一个常见的用例是在系统中创建User
对象时创建UserProfile
对象。
您可以注册一个post_save
信号,该信号会创建一个UserProfile
对象,该对象对应于系统中的每个User
。
信号是一种保持模块化和明确的方式。 (如果我 save
或更改 ModelB
中的某些内容,请明确通知 ModelA
)
为了更好地回答这个问题,我将考虑更具体的现实世界示例。同时,希望对您有所帮助
【讨论】:
感谢您的详细回答。之所以使用post_save
创建UserProfile
是因为可以在post_save 中检查实例是否为created
?(而不是在pre_save 中,保存)
您可能想补充一下 pre_save 或 post_save 本身与事务无关的答案。如果您使用 get_or_create 或请求级事务,post_save 将发生在事务内部,而不是在它之后。根据数据库,您可以使用一些 post_commit 信号实现。【参考方案2】:
不要忘记递归风险。 如果您在 instance.save() 调用中使用 post_save 方法,而不是 .update 方法,您应该断开您的 post_save 信号:
Signal.disconnect(接收方=无,发送方=无, dispatch_uid=None)[source] 断开接收器与信号的连接, 调用 Signal.disconnect()。论据如中所述 信号连接()。如果接收器是,该方法返回 True 如果没有断开连接,则为 False。
receiver 参数指示注册的接收器断开连接。 如果 dispatch_uid 用于识别接收者,则可能为 None。
...然后再次连接。
update() 方法不发送 pre_ 和 post_ 信号,请记住这一点。
【讨论】:
【参考方案3】:pre_save
在事务保存之前使用。
post_save
事务保存后使用。
您可以使用pre_save
,例如,如果您有FileField
或ImageField
,并查看file
或image
是否真的存在。
当您有一个UserProfile
并且您想在创建一个新的User
时创建一个新的post_save
,您可以使用它。
【讨论】:
对于您的pre_save
示例,您提供了一个检查文件是否存在的示例,使用信号或覆盖保存方法哪个更好?因为如果我在pre_save
信号中添加验证,我会遇到向我的表单提出错误的问题。
@Keda87 如果你使用表单,我会去覆盖表单的验证功能。
不! post_save 通常在原子块中调用。这意味着 post_save 发生在交易内部。以上是关于何时在 django 中使用 pre_save、save、post_save?的主要内容,如果未能解决你的问题,请参考以下文章
Django:如何使用 pre_save 信号更新模型实例?
无法使用 pre_save 信号在 django 模型中保存相关对象
如何使用 Django 信号(Pre_save,Post_save)从“B”模型的 ImageField 设置“A”模型的 ImageField
将pre_save信号更改为post_save?Django