Django pre_save信号 - 异常会导致事务失败吗?
我想在创建用户之前做一些自定义的操作,所以我想到了使用 pre_save
信号来实现。如果其中某个操作出错了,就应该停止这个过程,不再创建用户。
这样做可以吗?如果这个步骤出错了,会不会中止保存用户(这是我想要的效果)?我觉得应该可以,但找不到相关的文档。
获取未来用户的 ID 最好的方法是什么?我理解在 pre-save 阶段用户的 ID 还不存在,但我需要它作为一些额外操作的输入。
谢谢
2 个回答
这里有两个部分的回答:
首先,在pre_save()信号中抛出一个异常会停止调用save()方法。比如,我在我的pre_save()里这样做:
if SOME_TEST: raise exceptions.ParseError(detail="I reject your data. Here is why.")
注意:这里使用的是DRF的异常处理,但我相信你知道怎么抛出你想要的任何异常。
你可以使用post_save()信号在save()方法之后获取用户的ID。不过,如果这样不适合你,下面是我最初的解释,介绍一些在pre_save()中实现你想要的功能的方法:
在pre_save中,你可以访问User.objects.all()(当然前提是你导入了User模型)。如果你使用的是标准的User模型,那么User.id的值是自动递增的。所以如果你需要知道新用户的ID将会是什么,只需获取数据库中当前最高的User.id(也就是最后创建的用户的ID)。这里有一个简单的查询来做到这一点:
last_user = User.objects.latest('id')
然后,当然,last_user.id
会给你最后创建的用户的ID值,如果你在这个值上加一,你就得到了下一个用户的ID。当然,如果你的网站访问量很大,可能会出现同时创建用户的问题。风险在于,这个值可能会被两个(或更多)用户创建尝试获取,导致其中一个(或多个)结果出错。
当然,你也可以设置另一个字段为primary_key=True
,这样就会替代模型中的id
字段。然后你可以设计任何你能想到的索引机制!你可以使用某个独特特征的哈希值。例如:User.username
有唯一约束,你可以将其哈希或十六进制编码为一个数字ID,以预先确定User.id
。或者你可以保留id字段,并在pre_save中通过给obj.id
赋值来手动设置它。这个值可以是你想要的任何东西,甚至是一个哈希值!