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

如何用pytest测试Django文件上传?解决bytes对象JSON序列化报错

解决JSON序列化bytes对象的问题(Django+pytest文件上传测试)

JSON原生不支持序列化bytes类型,直接传递会触发TypeError: Object of type bytes is not JSON serializable错误。以下是两种可行的解决方案:


方案1:Base64编码后用JSON传输

适合接口要求必须使用JSON格式的场景,通过将二进制数据转成base64字符串实现兼容。

测试代码修改

导入base64模块,把bytes文件内容编码为字符串后再序列化:

import base64
import json

def test_file_upload(self):
    # 将bytes编码为base64字符串(需decode转成JSON支持的str类型)
    encoded_file = base64.b64encode(file_content).decode('utf-8')
    request = self.client.patch(
        "/fake-url/",
        json.dumps({"file": encoded_file}),
        content_type="application/json",
    )
    # 断言请求状态
    assert request.status_code == 200

后端视图解码处理

视图中需要将接收到的base64字符串解码回bytes,再转换为Django可处理的文件对象:

import base64
import json
from django.http import JsonResponse
from django.core.files.uploadedfile import InMemoryUploadedFile
import io

def file_upload_view(request):
    if request.method == 'PATCH':
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({'error': '无效的JSON格式'}, status=400)
        
        encoded_file = data.get('file')
        if not encoded_file:
            return JsonResponse({'error': '缺少文件数据'}, status=400)
        
        # 解码base64字符串
        try:
            file_content = base64.b64decode(encoded_file)
        except ValueError:
            return JsonResponse({'error': '无效的base64数据'}, status=400)
        
        # 转换为InMemoryUploadedFile,兼容Django文件处理逻辑
        file_obj = InMemoryUploadedFile(
            io.BytesIO(file_content),
            field_name='file',
            name='自定义文件名.ext',  # 替换为实际文件名
            content_type='application/octet-stream',  # 替换为实际文件MIME类型
            size=len(file_content),
            charset=None
        )
        
        # 后续逻辑:保存到模型或磁盘
        # your_model_instance.file_field.save(file_obj.name, file_obj)
        
        return JsonResponse({'success': True})

方案2:使用multipart/form-data上传(更推荐)

如果接口支持标准文件上传格式,直接用Django测试客户端的multipart格式上传,无需JSON序列化,逻辑更简洁。

测试代码修改

用BytesIO包装bytes内容,模拟真实文件对象:

from io import BytesIO

def test_file_upload(self):
    file_obj = BytesIO(file_content)
    file_obj.name = 'test_file.txt'  # 设置文件名
    
    request = self.client.patch(
        "/fake-url/",
        {'file': file_obj},
        format='multipart'
    )
    assert request.status_code == 200

后端视图处理

直接通过request.FILES获取文件对象,和常规文件上传逻辑完全一致:

from django.http import JsonResponse

def file_upload_view(request):
    if request.method == 'PATCH':
        file_obj = request.FILES.get('file')
        if not file_obj:
            return JsonResponse({'error': '缺少文件'}, status=400)
        
        # 直接处理文件对象,比如保存到模型
        # your_model_instance.file_field.save(file_obj.name, file_obj)
        
        return JsonResponse({'success': True})

注意事项

  • Base64编码会使数据体积增加约33%,超大文件不建议用JSON+Base64的方式
  • 优先选择multipart/form-data格式,这是文件上传的标准方案,代码更易维护

内容的提问来源于stack exchange,提问作者Mohamed Ibrahim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 05:05:30