Django FileField上传:如何在插入数据库前验证PDF文件?
解决方案:在不写入数据库的前提下验证上传的PDF文件
你不需要等到调用perform_create获取重命名后的文件名再验证PDF,因为上传的文件在验证阶段已经是一个可直接访问的UploadedFile对象,直接验证这个对象的内容即可,完全无需提前写入数据库。
方法一:在序列化器中添加字段验证(推荐)
把PDF验证逻辑放到序列化器的字段验证方法里,符合DRF的规范,验证不通过会直接返回错误,不会触发后续的数据库写入:
class DrawingSerializer(ModelSerializer): drawing = serializers.FileField() def validate_drawing(self, value): # value 就是上传的文件对象 try: # 直接读取文件流验证PDF有效性 with fitz.open(stream=value.read(), filetype="pdf") as doc: # 可选:额外验证PDF是否有内容 if doc.page_count <= 0: raise serializers.ValidationError("PDF文件无有效内容") # 重置文件指针到开头,避免后续保存时无法读取文件 value.seek(0) except Exception as e: raise serializers.ValidationError(f"无效的PDF文件: {str(e)}") return value class DrawingViewSet(viewsets.ModelViewSet): queryset = m.Drawing.objects.all() serializer_class = s.DrawingSerializer # 不需要重写create方法,默认逻辑即可
方法二:在ViewSet的create方法中提前验证
如果不想修改序列化器,也可以在perform_create之前直接验证上传的文件:
from rest_framework import status from rest_framework.response import Response from rest_framework import serializers class DrawingViewSet(viewsets.ModelViewSet): queryset = m.Drawing.objects.all() serializer_class = s.DrawingSerializer def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 获取验证后的文件对象 uploaded_file = serializer.validated_data['drawing'] # 验证PDF try: # 方式1:通过临时文件路径打开 doc = fitz.open(uploaded_file.temporary_file_path()) # 方式2:通过文件流打开(适合内存中的上传文件) # with fitz.open(stream=uploaded_file.read(), filetype="pdf") as doc: if doc.page_count <= 0: raise ValueError("PDF文件无内容") # 用文件流的话要重置指针 uploaded_file.seek(0) except Exception as e: raise serializers.ValidationError(f"无效的PDF文件: {str(e)}") # 验证通过后再写入数据库 self.perform_create(serializer) return Response(serializer.data, status=status.HTTP_201_CREATED)
核心逻辑说明
- 上传的文件在
serializer.is_valid()通过后,已经被封装成UploadedFile对象,存储在serializer.validated_data['drawing']中。 - 不管最终文件会被重命名成什么,文件内容和上传时完全一致,所以直接验证这个对象的内容就足够,不需要依赖最终的文件名。
- 验证失败时抛出
ValidationError,会直接返回错误响应,不会执行perform_create,也就不会向数据库插入无效记录。
内容的提问来源于stack exchange,提问作者whitebear
相关产品推荐
相关产品推荐

