use*_*478 0 database django postgresql transactions django-models
在我的Django应用程序中,我具有从数据库中删除模型的单个实例的代码。两个并发请求都可能同时尝试删除同一模型。在这种情况下,我希望一个请求成功而另一个请求失败。我怎样才能做到这一点?
问题在于,当使用删除实例时delete()
,Django不会返回有关命令是否成功的任何信息。此代码说明了问题:
b0 = Book.objects.get(id=1)
b1 = Book.objects.get(id=1)
b0.delete()
b1.delete()
Run Code Online (Sandbox Code Playgroud)
这两个delete()
命令中只有一个实际上删除了该对象,但是我不知道哪个。不会引发任何异常,也不会返回任何指示命令成功的信息。在纯SQL中,该命令将返回删除的行数,如果该值为0,我知道删除失败。
我将PostgreSQL与默认的Read Commited隔离级别配合使用。我对此级别的理解是,每个命令(SELECT,DELETE等)都可以看到数据库的快照,但是下一个命令可以看到数据库的不同快照。我相信这意味着我不能做这样的事情:
# I believe this wont work
@commit_on_success
def view(request):
try:
book = Book.objects.get(id=1)
# Possibility that the instance is deleted by the other request
# before we get to the next delete()
book.delete()
except ObjectDoesntExist:
# Already been deleted
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
您可以使用QuerySet.delete而不是Model.delete将约束直接放入SQL DELETE语句中:
Book.objects.filter(pk=1).delete()
Run Code Online (Sandbox Code Playgroud)
这根本不会发出SELECT查询,只是以下方面:
DELETE FROM Book WHERE id=1;
Run Code Online (Sandbox Code Playgroud)
这样可以处理两个并发请求同时删除同一条记录的竞争状况,但是并不能让您知道删除是否先到达了那里。为此,您必须获取原始光标(django允许您执行此操作),.execute()上面的DELETE自己,然后获取光标的rowcount属性,如果您不打算删除任何内容,则该值为0。