You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:15:54