如何用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
相关产品推荐
相关产品推荐

