Angular7+Django Rest3.9使用BinaryField上传图片报TypeError错误求助
解决DRF BinaryField处理上传文件时的TypeError问题
你遇到的这个错误,核心原因有两个:一是序列化器的初始化方式错误,二是BinaryField默认无法直接处理上传的文件对象。咱们一步步来解决:
先看原代码的关键错误
你的视图里创建序列化器时用了serializer = UserSerializer(request.data),这是不对的——ModelSerializer要反序列化创建新实例,必须把数据传给data参数,也就是serializer = UserSerializer(data=request.data)。这会导致serializer.is_valid()无法正确执行,也是后续错误的诱因之一。
为什么会出现TypeError: 'bytes' object cannot be interpreted as an integer?
当你上传图片时,request.data里的avatar是InMemoryUploadedFile对象,而DRF的BinaryField默认只接受原始的bytes数据。直接把文件对象传给它,内部的字段验证逻辑会尝试把文件对象当作整数处理,从而抛出这个错误。
解决方案一:在视图中手动处理文件转字节
你可以在视图里先读取文件的字节内容,替换request.data里的avatar值,再传给序列化器:
from rest_framework import status from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.permissions import IsAuthenticated from .serializers import UserSerializer from django.contrib.auth import get_user_model class CreateUserView(APIView): permission_classes = (IsAuthenticated, ) def post(self, request, format=None): # 复制request.data(因为QueryDict是不可变对象) processed_data = request.data.copy() # 处理avatar字段:如果存在且不是空,读取文件字节 if 'avatar' in processed_data and processed_data['avatar']: avatar_file = processed_data['avatar'] processed_data['avatar'] = avatar_file.read() # 正确初始化序列化器,传入data参数 serializer = UserSerializer(data=processed_data) if serializer.is_valid(): user = serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) # 别忘了返回错误信息,方便调试 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
解决方案二:自定义字段自动处理文件转字节
如果不想在每个视图里重复写处理逻辑,可以自定义一个继承自BinaryField的字段,重写to_internal_value方法来自动处理文件对象:
from rest_framework import serializers class FileToBinaryField(serializers.BinaryField): def to_internal_value(self, data): # 判断传入的是否是文件对象(有read方法) if hasattr(data, 'read'): return data.read() # 如果是普通bytes,调用父类逻辑处理 return super().to_internal_value(data)
然后在序列化器里替换原来的avatar字段:
from rest_framework import serializers from django.contrib.auth import get_user_model class UserSerializer(serializers.ModelSerializer): # 使用自定义字段 avatar = FileToBinaryField(allow_null=True) class Meta: model = get_user_model() fields = '__all__'
这时候视图就可以简化成(只需要修正序列化器初始化的问题):
class CreateUserView(APIView): permission_classes = (IsAuthenticated, ) def post(self, request, format=None): print('request data:', request.data) # 正确传入data参数 serializer = UserSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
额外注意事项
- 请求Content-Type:Angular端上传文件时,必须设置请求的Content-Type为
multipart/form-data,并且用FormData来包装数据,否则DRF无法正确解析上传的文件。 - MySQL存储限制:Django的
BinaryField对应MySQL的BLOB类型,最大存储64KB数据。如果你的图片较大,建议改用models.LongBinaryField(对应MySQL的LONGBLOB,最大4GB)。 - 文件读取后的资源释放:
InMemoryUploadedFile在读取后会自动管理资源,一般不需要手动关闭,但如果是大文件转成磁盘临时文件的情况,可以调用avatar_file.close()来释放资源。
内容的提问来源于stack exchange,提问作者farid Maghraoui
相关产品推荐
相关产品推荐

