【发布时间】:2013-07-12 19:39:53
【问题描述】:
我知道我可以覆盖或定义 pre_save, save, post_save 以在保存模型实例时执行我想要的操作。
在什么情况下首选哪一个,为什么?
【问题讨论】:
标签: python django django-models django-signals
我知道我可以覆盖或定义 pre_save, save, post_save 以在保存模型实例时执行我想要的操作。
在什么情况下首选哪一个,为什么?
【问题讨论】:
标签: python django django-models django-signals
我尽量举例说明:
pre_save 和post_save 是模型发送的signals。简单来说,就是在模型的save 之前或之后采取的行动被调用。
一个savetriggers 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 中,保存)
不要忘记递归风险。 如果您在 instance.save() 调用中使用 post_save 方法,而不是 .update 方法,您应该断开您的 post_save 信号:
Signal.disconnect(接收方=无,发送方=无, dispatch_uid=None)[source] 断开接收器与信号的连接, 调用 Signal.disconnect()。论据如中所述 信号连接()。如果接收器是,该方法返回 True 如果没有断开连接,则为 False。
receiver 参数指示注册的接收器断开连接。 如果 dispatch_uid 用于识别接收者,则可能为 None。
...然后再次连接。
update() 方法不发送 pre_ 和 post_ 信号,请记住这一点。
【讨论】:
pre_save
在事务保存之前使用。
post_save
事务保存后使用。
您可以使用pre_save,例如,如果您有FileField 或ImageField,并查看file 或image 是否真的存在。
当您有一个UserProfile 并且您想在创建一个新的User 时创建一个新的post_save,您可以使用它。
【讨论】:
pre_save 示例,您提供了一个检查文件是否存在的示例,使用信号或覆盖保存方法哪个更好?因为如果我在pre_save 信号中添加验证,我会遇到向我的表单提出错误的问题。