I am using DRF, API View Class based view, post method.
Parameters are : file
Logic : Do some validation on file and save file progressively (different type of objects)
I am trying to rollback the transaction if exception happens while saving the rest of the file. I set 'ATOMIC_REQUESTS': True
class SaveXMlFile(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
parser_classes = [FormParser, MultiPartParser]
def post(self, request):
"""
Save xml file
---
# inputs
parameters:
- name: game_log_file
description: Game log file
type: file
required: true
paramType: post
allowMultiple: false
"""
try:
# import pdb; pdb.set_trace()
game_log_file = request.data['game_log_file']
file_store = FileStore.objects.create(uploaded_file=game_log_file)
xml_file_processing = ProcessXmlFile(file_store)
already_saved = xml_file_processing.was_file_saved()
player_exists = xml_file_processing.player_exists()
if already_saved:
file_store.delete()
return Response({"info": "File was saved previously, no action taken place this time."}, status=200)
if not player_exists:
file_store.delete()
return Response({"info": "No player exists in the database, ask your administrator to create some."}, status=200)
xml_file_processing.save()
file_store.delete()
return Response({"success": "File has been saved."}, status=status.HTTP_201_CREATED)
except Exception as err:
error = "{0}".format(str(err))
return JsonResponse({'exception': error}, status=500)
I am deliberately throwing exceptions when half of the file has been saved but committed transactions don't rollback even exception is raised in the process.
Any thoughts would be appreciated.
You should read a bit more about how transactions work with Django. Since you are catching the exception, Django will see that everything went fine and will commit the transaction, no matter what's your response code. Taken from https://docs.djangoproject.com/en/1.10/topics/db/transactions/#tying-transactions-to-http-requests:
It works like this. Before calling a view function, Django starts a transaction. If the response is produced without problems, Django commits the transaction. If the view produces an exception, Django rolls back the transaction.
So since you're catching the exception and returning an response, Django sees no reason to perform a rollback.
There are two independent things here. First of all, DRF will raise a 500 response by itself, when an error occurs (so there is no need to catch exception and raise a 500 explicitely). Second of all, you may also consider applying method_decorator like so:
from django.utils.decorators import method_decorator
from django.db.transaction import atomic
@method_decorator(atomic, name='dispatch')
class MyView(APIView):
....
The main rationale behind this is that using ATOMIC_REQUESTS set to True may not always be desirable due to performance penalty, but you still may want to wrap some particular views in atomic block. Of course in this case you could have used
with atomic():
... your code
because you have access to the method itself, but that is a bit of a digress :)
hope this helps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With