2016-01-11 45 views
7

我想创建一个视图,我保存一个对象,但我想撤消,如果引发一些异常保存。这是我试过的:Django - 回滚保存与交易原子

class MyView(View): 

    @transation.atomic 
    def post(self, request, *args, **kwargs): 
     try: 
      some_object = SomeModel(...) 
      some_object.save() 

      if something: 
       raise exception.NotAcceptable() 
       # When the workflow comes into this condition, I think the previous save should be undome 
       # Whant am I missing? 

     except exception.NotAcceptable, e: 
      # do something 

我在做什么错?即使在引发异常时some_object仍然在DataBase中。

回答

11

Atomicity Documentation

总之,@transaction.atomic将在数据库上执行事务,如果您的视图产生没有错误的响应。因为你自己捕捉异常,所以Django显示你的视图执行得很好。

如果赶上例外,你需要自己处理:Controlling Transactions

如果你需要产生故障的情况下适当的JSON响应:

from django.db import SomeError, transaction 

def viewfunc(request): 
    do_something() 

    try: 
     with transaction.atomic(): 
      thing_that_might_fail() 
    except SomeError: 
     handle_exception() 

    render_response() 
+0

此视图适用于API,因此我认为我需要处理任何可能的错误以提供propper json响应。有没有办法做到这一点与原子装饰? – Gocht

+0

与装饰者imho不同,因为它处理函数外的事务。上下文管理器的好例子! – jpic

+0

您必须在try ... except块中包含一个原子块,如答案中所示。如果需要,您也可以在视图上使用原子装饰器。 – Alasdair

5

但是,如果一个例外饰有transaction.atomic功能情况,那么你不要有什么关系,它会rollback automatically to the savepoint created by the decorator before running the your function,为documented

原子允许我们创建一个块在其中保证数据库的原子性的代码。如果代码块成功完成,则更改将提交给数据库。如果有异常,则更改将回滚。

如果异常是在钓到除块,那么就应该再上调原子捕获它,做回退,即:

try: 
     some_object = SomeModel(...) 
     some_object.save() 

     if something: 
      raise exception.NotAcceptable() 
      # When the workflow comes into this condition, I think the previous save should be undome 
      # Whant am I missing? 

    except exception.NotAcceptable, e: 
     # do something 
     raise # re-raise the exception to make transaction.atomic rollback 

另外,如果你想要更多的控制,您可以手动回滚到previously set savepoint,即:

class MyView(View): 
    def post(self, request, *args, **kwargs): 
     sid = transaction.savepoint() 
     some_object = SomeModel(...) 
     some_object.save() 

     if something: 
      transaction.savepoint_rollback(sid) 
     else: 
      try: 
       # In worst case scenario, this might fail too 
       transaction.savepoint_commit(sid) 
      except IntegrityError: 
       transaction.savepoint_rollback(sid) 
+0

这就是我,虽然,这是为什么我这样做了这个函数,但正如我在问题中所说的那样,当引发异常时,该对象仍然处于数据库事件中,是否有任何使用保存点的附加步骤? – Gocht

+0

也许是因为这个异常被except块所捕获,并且不会被重新引发,所以原子认为它是成功执行的函数。 – jpic

+0

如果我没有发现错误,我不能给出一个很好的答案。我怎样才能建立我的功能? – Gocht