如何实现文档上传失败时不向数据库写入数据?
问题需求
用户上传文档并点击提交时,文件需存储到指定文件夹,同时数据库创建包含相关信息的条目。要求实现:若文档未能成功上传到指定位置,则不执行数据库写入操作。
现有代码
serializer.py
class DocumentSerializer(serializers.ModelSerializer): class Meta: model = Request fields = ['file', 'doc_type'] def create(self, validated_data): msg = self.__construct_message_body() validated_data['type'] = Request.request_types[-1][0] validated_data['input_message'] = msg instance = ParseRequest.objects.create(**validated_data) msg['request_id'] = instance.id instance.input_message = msg instance.save() return instance
views.py
class DocumentView(CreateAPIView, ResponseViewMixin): parser_classes = (MultiPartParser, FileUploadParser,) serializer_class = DocumentSerializer def create(self, request, *args, **kwargs): try: data = request.data serializer = self.get_serializer( data=data, context={'request': request}) serializer.is_valid() serializer.save() except Exception as e: logger.error(e) return self.error_response(message=ERROR_RESPONSE['UPLOAD_DOCUMENT']) return self.success_response(message=SUCCESS_RESPONSE['UPLOAD_DOCUMENT'])
解决方案
要实现文件上传失败则不写入数据库的核心是确保文件上传的异常能被捕获,且数据库操作与文件上传原子化,具体修改如下:
1. 修复视图的验证逻辑
原代码中serializer.is_valid()仅返回布尔值,不会主动抛出异常,导致验证失败(如文件格式错误、大小超限)时仍会执行后续的serializer.save()。需改为:
serializer.is_valid(raise_exception=True)
这样验证失败时会直接抛出ValidationError,进入except块,避免执行数据库写入。
2. 确保文件上传与数据库操作的原子性
Django的FileField在模型保存时会自动处理文件上传,若上传失败(如磁盘满、权限不足)会抛出异常。结合Django的事务机制,可保证文件上传和数据库写入要么同时成功,要么同时回滚:
方式一:给序列化器的create方法添加事务装饰器
from django.db import transaction class DocumentSerializer(serializers.ModelSerializer): # ... 其他代码不变 ... @transaction.atomic def create(self, validated_data): msg = self.__construct_message_body() validated_data['type'] = Request.request_types[-1][0] validated_data['input_message'] = msg instance = ParseRequest.objects.create(**validated_data) msg['request_id'] = instance.id instance.input_message = msg instance.save() return instance
方式二:在视图层添加事务
from django.db import transaction class DocumentView(CreateAPIView, ResponseViewMixin): # ... 其他代码不变 ... @transaction.atomic def create(self, request, *args, **kwargs): try: data = request.data serializer = self.get_serializer( data=data, context={'request': request}) serializer.is_valid(raise_exception=True) serializer.save() except Exception as e: logger.error(e) return self.error_response(message=ERROR_RESPONSE['UPLOAD_DOCUMENT']) return self.success_response(message=SUCCESS_RESPONSE['UPLOAD_DOCUMENT'])
3. 额外优化:明确文件上传的异常捕获
若自定义了文件上传逻辑(而非Django默认的FileField处理),需确保上传失败时主动抛出异常,这样才能触发except块的逻辑,终止数据库写入。
原理说明
- 当
serializer.save()调用时,会触发序列化器的create方法,此时ParseRequest.objects.create()会执行模型的保存操作,同时完成文件上传。 - 若文件上传过程中抛出异常,事务会自动回滚,数据库不会创建新条目。
- 视图层的
except块会捕获所有异常,返回上传失败的响应。
内容的提问来源于stack exchange,提问作者ReaL_HyDRA
相关产品推荐
相关产品推荐

