In Django Rest Framework how to make a function base view roll back every change made if somethings fails

22 Views Asked by At

I have a api endpoint that the user will send a key pair of file_field: File in the multipart content type. The function need to update every document and create a history about the change. Then It should complete the session that the user used to do this change. If a document couldn't be updated or a historic couldn't be created all the operations and changes should roll back how to archive this. This is my current function base view:

@transaction.atomic
@api_view(['POST'])
@parser_classes([JSONParser, MultiPartParser])
@permission_classes([HasSpecialSessionPermission])
def update_documents(request):
    user = request.user
    special_session = SpecialSessionConfiguration.objects.filter(user=user, completed=False).first()
    lot = DefaultLotModel.objects.filter(user=user, call__active=True).first()
    for key, uploaded_file in request.FILES.items():
        try:
            validate_file_size(uploaded_file)
            if key != 'financial_form' and key != 'power_point':
                validate_file_extension(uploaded_file)
        except ValidationError as e:
            return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST)

        if special_session.special_session_fields.filter(
                field_name=get_field_number(SPECIAL_SESSION_FIELD, key)).exists():
            if hasattr(lot, key):
                current_file = getattr(lot, key)
                if current_file:
                    setattr(lot, key, uploaded_file)
                    LotDocumentHistory.objects.create(
                        lot=lot,
                        old_file=current_file,
                        field_name=key,
                    )

                setattr(lot, key, uploaded_file)
                lot.save()
            else:
                for child_field in ['first_lots', 'second_lots', 'third_lots']:
                    child_lot = getattr(lot, child_field, None)
                    if child_lot and hasattr(child_lot, key):
                        current_file = getattr(child_lot, key)
                        if current_file:
                            LotDocumentHistory.objects.create(
                                lot=lot,
                                old_file=current_file,
                                field_name=key,
                            )

                        setattr(child_lot, key, uploaded_file)
                        child_lot.save()
        elif special_session.extra_files:
            try:
                data = {'name': key, 'file': uploaded_file, 'lot': lot.pk}
                serializer = ExtraFileSerializer(data=data)
                serializer.is_valid(raise_exception=True)
                serializer.save()
            except ValidationError as ve:
                error_dict = ve.get_full_details()
                response_data = {
                    ERROR_TYPE: VALIDATION_ERROR,
                    ERRORS: error_dict,
                    MESSAGE: get_validation_error_message(error_dict)
                }
                return Response(data=response_data, status=status.HTTP_400_BAD_REQUEST)
    special_session.completed = True
    special_session.save()

    return Response(data={'lot_id': lot.pk}, status=status.HTTP_200_OK)

If one of the update and saves fails all operations should go back

0

There are 0 best solutions below