2016-01-11 47 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