2011-01-21 55 views
0

在我的Django应用程序中,我有从数据库中删除模型的单个实例的代码。有两种并发请求都有可能试图同时删除同一个模型。在这种情况下,我希望一个请求成功,另一个请求失败。我怎样才能做到这一点?使用事务安全地从数据库中删除Django模型

问题是,当使用delete()删除实例时,Django不会返回有关命令是否成功的任何信息。此代码说明了这个问题:

b0 = Book.objects.get(id=1) 
b1 = Book.objects.get(id=1) 
b0.delete() 
b1.delete() 

这两个delete()命令只有一个真正删除的对象,但我不知道是哪一个。不会抛出异常,并且不会返回任何内容来指示命令的成功。在纯SQL中,该命令将返回删除的行数,如果该值为0,我会知道我的删除失败。

我正在使用默认的Read Commited隔离级别的PostgreSQL。我对这个级别的理解是,每个命令(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 

任何想法?

回答

4

你可以把约束权到SQL使用的,而不是Model.delete QuerySet.delete DELETE语句:

Book.objects.filter(pk=1).delete() 

这不会发出SELECT查询所有,只是沿着线的东西:

DELETE FROM Book WHERE id=1; 

,处理删除同一记录在同一时间两个并发请求的竞争状态,但它不会让你知道你是否删除最先到达那里。为此,你必须得到原始光标(其中django lets you do),.execute()上面的DELETE自己,然后拿起光标的rowcount属性,如果你没有结束删除任何事情,它将是0。