何时在 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_savepost_save 是模型发送的signals。简单来说,就是在模型的save 之前或之后采取的行动被调用。

一个savetriggers the following steps

发出预保存信号。 预处理数据。 大多数字段不进行预处理 - 字段数据保持原样。 为数据库准备数据。 将数据插入数据库。 发出保存后信号。

Django 确实提供了一种方法来覆盖这些信号。

现在,

pre_save 信号可以在实际保存到数据库之前被覆盖以进行某些处理 - 示例:(我不知道pre_save 最适合我的最佳示例)

假设您有一个ModelA,它存储对ModelB 的所有对象的引用,这些对象尚未被编辑。为此,您可以在调用ModelBsave 方法之前注册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,例如,如果您有FileFieldImageField,并查看fileimage 是否真的存在。

当您有一个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

为啥以及何时使用 Django mark_safe() 函数

Django:信号的使用