From 05cc9e77567101c5305db91e1123787696917e4b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 21 Aug 2014 12:42:08 +0100 Subject: [PATCH] Mark for transaction rollback after APIException occurs --- rest_framework/compat.py | 12 ++++++++++++ rest_framework/views.py | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index fa0f0bfb1..e82530f8f 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -99,6 +99,18 @@ def get_concrete_model(model_cls): return model_cls +def set_rollback(transaction): + if hasattr(transaction, 'set_rollback'): + # If running in >=1.6 then mark a rollback as required, + # and allow it to be handled by Django. + transaction.set_rollback(True) + elif transaction.is_managed(): + # Otherwise handle it explicitly if in managed mode. + if transaction.is_dirty(): + transaction.rollback() + transaction.leave_transaction_management() + + # View._allowed_methods only present from 1.5 onwards if django.VERSION >= (1, 5): from django.views.generic import View diff --git a/rest_framework/views.py b/rest_framework/views.py index 23df3443f..aacc433ee 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -4,11 +4,12 @@ Provides an APIView class that is the base of all views in REST framework. from __future__ import unicode_literals from django.core.exceptions import PermissionDenied +from django.db import transaction from django.http import Http404 from django.utils.datastructures import SortedDict from django.views.decorators.csrf import csrf_exempt from rest_framework import status, exceptions -from rest_framework.compat import smart_text, HttpResponseBase, View +from rest_framework.compat import set_rollback, smart_text, HttpResponseBase, View from rest_framework.request import Request from rest_framework.response import Response from rest_framework.settings import api_settings @@ -368,6 +369,8 @@ class APIView(View): if response is None: raise + # We've swallowed the exception, but we should mark it for rollback. + set_rollback(transaction) response.exception = True return response